參考鏈接:
從一個簡單的AIDL實現(xiàn)看binder原理(一)簡單的AIDL實現(xiàn)
從一個簡單的AIDL實現(xiàn)看binder原理(二)bindService的調用過程
從一個簡單的AIDL實現(xiàn)看binder原理(三)bindService調用過程中Binder的傳遞
從一個簡單的AIDL實現(xiàn)看binder原理(四)bindService調用過程中Binder的寫入
從一個簡單的AIDL實現(xiàn)看binder原理(五)bindService調用過程中Binder的轉換
從一個簡單的AIDL實現(xiàn)看binder原理(六)Android系統(tǒng)中Binder的運行
從一個簡單的AIDL實現(xiàn)看binder原理(七)Binder的一次拷貝和內存限制
首先在main目錄下新建aidl文件夾,如下圖所示:
然后在java文件夾中創(chuàng)建Model類,需實現(xiàn)Parcelable接口:
package org.hrcy.ipctest;
import android.os.Parcel;
import android.os.Parcelable;
public class Student implements Parcelable {
private int code;
private String name;
public Student(int code, String name) {
this.code = code;
this.name = name;
}
protected Student(Parcel in) {
code = in.readInt();
name = in.readString();
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static final Creator<Student> CREATOR = new Creator<Student>() {
@Override
public Student createFromParcel(Parcel in) {
return new Student(in);
}
@Override
public Student[] newArray(int size) {
return new Student[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(code);
dest.writeString(name);
}
}
接下來在aidl文件夾中創(chuàng)建aidl文件,名字隨意踩晶,創(chuàng)建后長這樣:
// IAIDLInterface.aidl
package org.hrcy.ipctest;
// Declare any non-default types here with import statements
interface IAIDLInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
其中basicTypes方法表明了AIDL過程支持的基本數(shù)據(jù)類型,用不到刪除即可
需要注意的是,如果在AIDL文件中使用了自定義的Parcelable類型,則需要在aidl文件夾中定義一個和這個類型同名的aidl文件,并表明該類型為parcelable,代碼如下:
//Student.aild
package org.hrcy.ipctest;
parcelable Student;
需要注意,package 需要與自定義類型的package一致
接下來,在IAIDLInterface文件中手動導入Student類型并定義我們在跨進程通信時所需要的方法:
// IAIDLInterface.aidl
package org.hrcy.ipctest;
// Declare any non-default types here with import statements
import org.hrcy.ipctest.Student;
interface IAIDLInterface {
List<Student> getStudent();
void setStudent(in Student student);
}
除了基本類型數(shù)據(jù)饥悴,其它類型的參數(shù)必須標上方向:in、out盲再、inout西设。in 表示輸入;out 表示輸出答朋;inout 表示輸入輸出型的參數(shù)贷揽,注意按需使用,因為 out 以及 inout 在底層實現(xiàn)是需要一定開銷的梦碗。
完成之后點擊菜單中Build -> Make Project 選項
在Make過程完成之后禽绪,會根據(jù)定義的aidl文件自動生成所需的java類,路徑如下:
我們看一下IAIDLInterface的代碼:
/*
* This file is auto-generated. DO NOT MODIFY.
*/
package org.hrcy.ipctest;
public interface IAIDLInterface extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements org.hrcy.ipctest.IAIDLInterface {
private static final java.lang.String DESCRIPTOR = "org.hrcy.ipctest.IAIDLInterface";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an org.hrcy.ipctest.IAIDLInterface interface,
* generating a proxy if needed.
*/
public static org.hrcy.ipctest.IAIDLInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof org.hrcy.ipctest.IAIDLInterface))) {
return ((org.hrcy.ipctest.IAIDLInterface) iin);
}
return new org.hrcy.ipctest.IAIDLInterface.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
case TRANSACTION_getStudent: {
data.enforceInterface(descriptor);
java.util.List<org.hrcy.ipctest.Student> _result = this.getStudent();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_setStudent: {
data.enforceInterface(descriptor);
org.hrcy.ipctest.Student _arg0;
if ((0 != data.readInt())) {
_arg0 = org.hrcy.ipctest.Student.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.setStudent(_arg0);
reply.writeNoException();
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements org.hrcy.ipctest.IAIDLInterface {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public java.util.List<org.hrcy.ipctest.Student> getStudent() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<org.hrcy.ipctest.Student> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getStudent, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(org.hrcy.ipctest.Student.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void setStudent(org.hrcy.ipctest.Student student) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((student != null)) {
_data.writeInt(1);
student.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_setStudent, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_setStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public java.util.List<org.hrcy.ipctest.Student> getStudent() throws android.os.RemoteException;
public void setStudent(org.hrcy.ipctest.Student student) throws android.os.RemoteException;
}
接下來創(chuàng)建一個Service洪规,注意要在AndroidManifest文件中標明Service的進程為不同進程:
<service android:name=".RemoteService"
android:process=":remote"/>
process的值隨意印屁。
Service的代碼如下:
package org.hrcy.ipctest;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.Nullable;
public class RemoteService extends Service {
private List<Student> studentList = new ArrayList<>();
@Override
public void onCreate() {
super.onCreate();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return stub;
}
IAIDLInterface.Stub stub = new IAIDLInterface.Stub() {
@Override
public List<Student> getStudent() throws RemoteException {
return studentList;
}
@Override
public void setStudent(Student student) throws RemoteException {
studentList.add(student);
}
};
}
再看一下Activity的代碼:
package org.hrcy.ipctest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button startBtn;
private EditText codeEt;
private EditText nameEt;
private Button addBtn;
private Button getBtn;
private TextView studentListText;
private IAIDLInterface proxy;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startBtn = findViewById(R.id.btn_start);
codeEt = findViewById(R.id.et_code);
nameEt = findViewById(R.id.et_name);
addBtn = findViewById(R.id.btn_add);
getBtn = findViewById(R.id.btn_get);
studentListText = findViewById(R.id.text_student_list);
initListener();
}
private void initListener() {
startBtn.setOnClickListener(this);
addBtn.setOnClickListener(this);
getBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_start:
bindService(new Intent(this, RemoteService.class), connection, BIND_AUTO_CREATE);
break;
case R.id.btn_add:
int code = Integer.valueOf(codeEt.getText().toString().trim());
String name = nameEt.getText().toString().trim();
try {
proxy.setStudent(new Student(code, name));
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case R.id.btn_get:
try {
List<Student> students = proxy.getStudent();
if (students != null && students.size() > 0) {
StringBuilder sb = new StringBuilder();
for (Student student : students) {
sb.append(student.toString());
sb.append("\n");
}
studentListText.setText(sb.toString());
}
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
proxy = IAIDLInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
}
至此,一個簡單的AIDL實現(xiàn)過程就完成了