参考链接:
从一个简单的AIDL实现看binder原理(一)简单的AIDL实现
从一个简单的AIDL实现看binder原理(二)bindService的调用过程
从一个简单的AIDL实现看binder原理(三)bindService调用过程中Binder的传递
从一个简单的AIDL实现看binder原理(四)bindService调用过程中Binder的写入
从一个简单的AIDL实现看binder原理(五)bindService调用过程中Binder的转换
从一个简单的AIDL实现看binder原理(六)Android系统中Binder的运行
从一个简单的AIDL实现看binder原理(七)Binder的一次拷贝和内存限制
首先在main目录下新建aidl文件夹,如下图所示:
然后在java文件夹中创建Model类,需实现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文件夹中创建aidl文件,名字随意,创建后长这样:
// 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过程支持的基本数据类型,用不到删除即可
需要注意的是,如果在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);
}
除了基本类型数据,其它类型的参数必须标上方向:in、out、inout。in 表示输入;out 表示输出;inout 表示输入输出型的参数,注意按需使用,因为 out 以及 inout 在底层实现是需要一定开销的。
完成之后点击菜单中Build -> Make Project 选项
在Make过程完成之后,会根据定义的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;
}
接下来创建一个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实现过程就完成了