一、AIDL
安卓接口定义语言,用于进程间进行ipc通信。
详细:Android 接口定义语言 (AIDL) | Android 开发者 | Android Developers
- AIDL接口是直接函数调用。
- 本地进程的调用在发起调用的同一线程执行。
- AIDL接口必须线程安全。
安卓的序列化
❤️Android 序列化(Serializable和Parcelable) ❤️ - 掘金 (juejin.cn)
Parcelable和Bundle的区别
Parcelable 和 Bundle | Android 开发者 | Android Developers
android binder机制中Parcel容器到底做了什么? - 知乎 (zhihu.com)
二、如何使用AIDL?
1、服务端
编写parcelable对象
public class NumberData implements Parcelable {
public int num1;
public int num2;
protected NumberData(Parcel in) {
readFromParcel(in);
}
protected NumberData() {
}
public static final Creator<NumberData> CREATOR = new Creator<NumberData>() {
@Override
public NumberData createFromParcel(Parcel in) {
return new NumberData(in);
}
@Override
public NumberData[] newArray(int size) {
return new NumberData[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel out, int i) {
out.writeInt(num1);
out.writeInt(num2);
}
public void readFromParcel(Parcel in) {
num1 = in.readInt();
num2 = in.readInt();
}
}
编写 .aidl文件
interface MyAidlInterface {
// 直接传入两个值进行相加
int add(int a,int b);
// 传入一个对象:a和b,相加后返回
int add1(in NumberData data);
}
实现接口
// 实现.stub()
private final MyAidlInterface.Stub mBinder = new MyAidlInterface.Stub(){
@Override
public int add(int a, int b) throws RemoteException {
return a + b;
}
//通过ipc接受对象
@Override
public int add1(NumberData data) throws RemoteException {
return data.num1 + data.num2;
}
};
- 如果接口的方法调用时间很长,应提前做好在客户端调用时新开线程处理的准备
- 保证线程安全
- 抛出的异常不会传递给调用方(客户端)
暴露接口,供客户端使用
public class MyService extends Service {
public MyService(){
}
// 通过onBind暴露接口,提供客户端调用
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
// 实现.stub()
private final MyAidlInterface.Stub mBinder = new MyAidlInterface.Stub(){
@Override
public int add(int a, int b) throws RemoteException {
return a + b;
}
//通过ipc接受对象
@Override
public int add1(NumberData data) throws RemoteException {
return data.num1 + data.num2;
}
};
}
同时也需要暴露parcelable对象
package com.zx.binderserver;
parcelable NumberData;
开启服务,并配置权限
项目结构:
2、客户端
创建同样目录结构的.adil接口
从server复制相同的代码到client
创建service,并实现接口
public class MyService extends Service {
private final Binder mbinder = new MyBinder();
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d("MainActivity", "onBind()");
return mbinder;
}
private class MyBinder extends MyAidlInterface.Stub {
@Override
public int add(int a, int b) throws RemoteException {
return a + b;
}
@Override
public int add1(NumberData data) throws RemoteException {
return data.num1 + data.num2;
}
}
}
创建serviceConnection进行调用
// MainActivity.java中
// 需要编译后,才可以识别到进行调用
private MyAidlInterface mService;
private boolean isConn = false;
private final ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.d(TAG, "onServiceConnected()");
mService = MyAidlInterface.Stub.asInterface(iBinder);
isConn = true;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
unbindService(conn);
isConn = false;
}
};
调用业务逻辑
public class MainActivity extends AppCompatActivity {
private boolean isConn = false;
private final String TAG = this.getClass().getSimpleName();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
Log.d(TAG, "onCreate()");
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_main);
// 未绑定服务,进行绑定
if (!isConn) {
mBindService();
isConn = true;
}
Button btn = this.findViewById(R.id.btn);
btn.setOnClickListener(view -> {
try {
TextView et1 = this.findViewById(R.id.et_1);
TextView et2 = this.findViewById(R.id.et_2);
Log.d(TAG, "et1=" + et1.getText() + ",et2=" + et2.getText());
// 判空
if (!TextUtils.isEmpty(et1.getText()) && !TextUtils.isEmpty(et1.getText())) {
int num1 = Integer.parseInt(et1.getText().toString());
int num2 = Integer.parseInt(et2.getText().toString());
Log.d(TAG, "a = " + num1 + ",b = " + num2);
// 远程进行计算结果
int res = mService.add(num1, num2);
Log.d(TAG, "res = " + res);
TextView tv = findViewById(R.id.tv);
// 展示结果
tv.setText(Integer.toString(res));
}
} catch (RemoteException e) {
e.printStackTrace();
}
});
Button btn1 = this.findViewById(R.id.btn1);
btn1.setOnClickListener(view -> {
try {
TextView et1 = this.findViewById(R.id.et_1);
TextView et2 = this.findViewById(R.id.et_2);
Log.d(TAG, "et1=" + et1.getText() + ",et2=" + et2.getText());
// 判空
if (!TextUtils.isEmpty(et1.getText()) && !TextUtils.isEmpty(et1.getText())) {
int num1 = Integer.parseInt(et1.getText().toString());
int num2 = Integer.parseInt(et2.getText().toString());
Log.d(TAG, "a = " + num1 + ",b = " + num2);
// 创建parcelable对象,存储需要相加的两个值
NumberData numberData = new NumberData();
numberData.setNum1(num1);
numberData.setNum2(num2);
// 调用远程的接口方法
int res = mService.add1(numberData);
Log.d(TAG, "res = " + res);
TextView tv = findViewById(R.id.tv);
// 展示结果
tv.setText(Integer.toString(res));
}
} catch (RemoteException e) {
e.printStackTrace();
}
});
}
private void mBindService(){
Log.d(TAG, "绑定服务....");
// 创建Intent,并添加action
Intent intent = new Intent("AIDL.server");
// 设置包名
intent.setPackage("com.zx.binderserver");
// 绑定服务
boolean isBind = bindService(intent, conn, Context.BIND_AUTO_CREATE);
Log.d(TAG, "isBind = " + isBind);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 销毁服务
if (isConn) {
unbindService(conn);
isConn = false;
}
}
}