零.前言
本片文章主要介绍Android AIDL的概念和使用,着重介绍AIDL的使用。
一.基本概念
什么是Binder:简单的来讲,我们可以将Binder看成Android进程间通信的一种方式,是Android的特性之一。
什么是ALDL:AIDL ( Android Interface Definition Language ) Android接口定义语言。AIDL是一种编程规范,用于生成在Android设备上两个进程通信的代码,内部是使用Binder实现的。
二.AIDL支持的数据类型
- Java基本数据类型:boolean char byte int long float double string
- Intent,Bundle,Bitmap,List和Map(集合存储的元素必须是AIDL支持的类型,服务端接收的实体必须是ArrayList和HashMap)
- 其他AIDL接口
- 实现Parcelable接口的可序列化引用类型
三.AIDL的使用
1.新建AIDL文件
工程Main目录下新建和java目录平级的aidl目录——新建包名——新建AIDL文件
示例如下:
*PluginData.aidl:
- 这里需要注意:在AIDL中使用的数据类型,除了基本数据、list和Map其他类型必须使用import关键字导入
package com.li.pluginapp;
import com.li.pluginapp.TestData;
interface PluginData {
String conversionJsonData(String formJsonData);
/**
* 除了基本数据类型,其他类型的参数都需要标上方向类型:in(输入), out(输出), inout(输入输出)
*/
void addTestData(in TestData data);
List getTestData();
}
2.声明Parcelable对象
- 自定义的数据类型,必须实现Parcelable接口
- 自定义的数据类型,必须创建一个和实体类同名的映射 aidl 文件,同时声明为parcelable类型
*TestData.java
package com.li.pluginapp;
import android.os.Parcel;
import android.os.Parcelable;
public class TestData implements Parcelable {
private int id;
private String jsonString;
protected TestData(Parcel in) {
id = in.readInt();
jsonString = in.readString();
}
public static final Creator CREATOR = new Creator() {
@Override
public TestData createFromParcel(Parcel in) {
return new TestData(in);
}
@Override
public TestData[] newArray(int size) {
return new TestData[size];
}
};
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getJsonString() {
return jsonString;
}
public void setJsonString(String jsonString) {
this.jsonString = jsonString;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(jsonString);
}
@Override
public String toString() {
return "TestData{" +
"id=" + id +
", jsonString='" + jsonString + '\'' +
'}';
}
}
*TestData.aidl
- 注意:这个TestData.aidl的包名必须和实体类一致
package com.li.pluginapp;
parcelable TestData;
3.服务端
- 创建进程通信的Service用来监听客户端进程的连接请求
- 生成Binder对象,实现aidl接口定义的方法
- onBinder方法返回Binder对象
*ServerService.java
package com.li.pluginapp;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
/**
* 服务端Service
*/
public class ServerService extends Service {
private ArrayList mData = new ArrayList<>();
private PluginData.Stub mBinder = new PluginData.Stub() {
@Override
public String conversionJsonData(String formJsonData) throws RemoteException {
return "已收到传送的JSON数据: " + formJsonData;
}
@Override
public void addTestData(TestData data) throws RemoteException {
mData.add(data);
Log.d("服务器:addTestData",data.toString());
}
@Override
public List getTestData() throws RemoteException {
Log.d("服务器:getTestData","");
return mData;
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
别忘了在manifest中注册,隐式调用配置下intent-filter
4.客户端
- 如果在不同的工程中,需要将aidl目录下所有文件复制一份到新工程中(服务端一样,包名需要一致)
- 自定义数据类型复制一份(服务端一样,包名需要一致)
- 调用bindService建立连接获得Binder对象
- 将Binder对象转换成对应aidl所属的类型,之后就可以调用aidl接口定义的方法了
Intent intent = new Intent("com.li.pluginapp.ServerService");
intent.setPackage("com.li.pluginapp");
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
iPluginDataManager = PluginData.Stub.asInterface(service);
for (int i = 0; i < 10; i++) {
iPluginDataManager.addTestData(new TestData(i, "测试数据" + i));
}
List testData = iPluginDataManager.getTestData();
Log.d("客户端发送的消息:", testData.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, BIND_AUTO_CREATE);
- 这里就不贴完整的代码,在另一工程中,所以需要隐式启动Intent,Android5.0之后需要指定包名转为显式调用,不然会报错
- onServiceConnected建立连接回调方法中会传递Binder对象,将其转换从aidl对象保存,之后就可以通过此aidl对象调用相应的方法了
这里可以看下服务端的打印日志,循环添加了10个数据:
07-21 16:08:10.212 28746-28758/com.li.pluginapp D/服务器:addTestData: TestData{id=0, jsonString='测试数据0'}
07-21 16:08:10.213 28746-28759/com.li.pluginapp D/服务器:addTestData: TestData{id=1, jsonString='测试数据1'}
07-21 16:08:10.213 28746-28815/com.li.pluginapp D/服务器:addTestData: TestData{id=2, jsonString='测试数据2'}
07-21 16:08:10.213 28746-28758/com.li.pluginapp D/服务器:addTestData: TestData{id=3, jsonString='测试数据3'}
07-21 16:08:10.213 28746-28759/com.li.pluginapp D/服务器:addTestData: TestData{id=4, jsonString='测试数据4'}
07-21 16:08:10.214 28746-28815/com.li.pluginapp D/服务器:addTestData: TestData{id=5, jsonString='测试数据5'}
07-21 16:08:10.214 28746-28758/com.li.pluginapp D/服务器:addTestData: TestData{id=6, jsonString='测试数据6'}
07-21 16:08:10.216 28746-28759/com.li.pluginapp D/服务器:addTestData: TestData{id=7, jsonString='测试数据7'}
07-21 16:08:10.216 28746-28815/com.li.pluginapp D/服务器:addTestData: TestData{id=8, jsonString='测试数据8'}
07-21 16:08:10.217 28746-28758/com.li.pluginapp D/服务器:addTestData: TestData{id=9, jsonString='测试数据9'}
可以看到,Activity 与 另外一个进程的 Service 通信成功了