概述
AIDL是Android Interface Definition Language的缩写,在某种意义上讲,AIDL其实是一个模板,有规范和约束的作用。实际上起作用的是根据AIDL而生产的实例代码。
AIDL与Java语音的接口十分的相似,也它也有一些几点特点:
- AIDL支持的数据格式支持8大基本数据类型(byte、char、short、int、long、float、double、boolean,String,CharSequence),支持的空间数据结构有List和Map。
- 数据流向标记。in、out、inout。in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。
- 手动导包。
在Android中,跨进程通信采用的Binder机制,而基于Binder来实现跨进程的方式通常是采用AIDL和Massenger。
两者的关系是:AIDL是基于Messenger,而Messenger是基于Binder的。
关于更多关于Binder机制的知识可参看《IPC机制》
AIDL具体实现
在AS中添加.aidl文件:
首先定义服务接口,IMyAidlInterface.aidl:
1
2
3
4
5
6
7
8
9
10
11
12// IMyAidlInterface.aidl
package com.zhouk.soft.mystudio;
//引用数据类型
import com.zhouk.soft.mystudio.entity.TestAidlBean;
interface IMyAidlInterface {
String AIDL_Service();
void addMyAidlBean(in TestAidlBean bean);//添加Bean到List里
List<TestAidlBean> getList();//获取List
}定义引用类型,TestAidlBean.aidl:
1
2
3
4// TestAidlBean.aidl
package com.zhouk.soft.mystudio.entity;
parcelable TestAidlBean;
注意,aidl引用数据类型必须与Java中对应的Bean相同包名
AIDL文件添加完成后Make Project一下。会根据IMyAidlInterface.aidl来生成IMyAidlInterface.java文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113public interface IMyAidlInterface extends android.os.IInterface {
/**
* Binder对象
*/
public static abstract class Stub extends android.os.Binder implements com.zhouk.soft.mystudio.IMyAidlInterface {
/**
* Cast an IBinder object into an com.zhouk.soft.mystudio.IMyAidlInterface interface,
* generating a proxy if needed.
*/
public static com.zhouk.soft.mystudio.IMyAidlInterface asInterface(android.os.IBinder obj) {
// ... ...
return new com.zhouk.soft.mystudio.IMyAidlInterface.Stub.Proxy(obj);
}
public android.os.IBinder asBinder() {
return this;
}
//收到Binder驱动通知后,Server 进程通过回调Binder对象onTransact()进行数据解包 & 调用目标方法
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_AIDL_Service: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.AIDL_Service();
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_addMyAidlBean: {
data.enforceInterface(DESCRIPTOR);
com.zhouk.soft.mystudio.entity.TestAidlBean _arg0;
if ((0 != data.readInt())) {
_arg0 = com.zhouk.soft.mystudio.entity.TestAidlBean.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addMyAidlBean(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getList: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.zhouk.soft.mystudio.entity.TestAidlBean> _result = this.getList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
}
//将结算结果返回 到Binder驱动
return super.onTransact(code, data, reply, flags);
}
// 1. Binder驱动根据 代理对象 沿原路 将结果返回 并通知Client进程获取返回结果
// 2. 通过代理对象 接收结果(之前被挂起的线程被唤醒)
private static class Proxy implements com.zhouk.soft.mystudio.IMyAidlInterface {//mRemote.transact()
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
public java.lang.String AIDL_Service() throws android.os.RemoteException {
// ... ...
mRemote.transact(Stub.TRANSACTION_AIDL_Service, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
// ... ...
return _result;
}
public void addMyAidlBean(com.zhouk.soft.mystudio.entity.TestAidlBean bean) throws android.os.RemoteException {
// ... ...
mRemote.transact(Stub.TRANSACTION_addMyAidlBean, _data, _reply, 0);
_reply.readException();
// ... ...
}
public java.util.List<com.zhouk.soft.mystudio.entity.TestAidlBean> getList() throws android.os.RemoteException {
// ... ...
mRemote.transact(Stub.TRANSACTION_getList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.zhouk.soft.mystudio.entity.TestAidlBean.CREATOR);
// ... ...
return _result;
}
}
// ... ...
}
public java.lang.String AIDL_Service() throws android.os.RemoteException;
public void addMyAidlBean(com.zhouk.soft.mystudio.entity.TestAidlBean bean) throws android.os.RemoteException;
public java.util.List<com.zhouk.soft.mystudio.entity.TestAidlBean> getList() throws android.os.RemoteException;
}定义进程服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45/**
* Created by ZhouKang on 2018/4/14
* 多进程,Server角色
*/
public class TestServerService extends Service {
private static final String TAG = "服务TestServerService";
private List<TestAidlBean> listBean;
public IBinder onBind(Intent intent) {
Log.e(TAG, "已开启service进程服务");
return myAidlInterface;
}
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
public void onCreate() {
super.onCreate();
listBean = new ArrayList<>();
}
IMyAidlInterface.Stub myAidlInterface = new IMyAidlInterface.Stub() {
public String AIDL_Service() throws RemoteException {
return "这是一条来自Service的消息";
}
public void addMyAidlBean(TestAidlBean bean) throws RemoteException {
listBean.add(bean);
Log.e(TAG, "已添加来自客户端的Bean");
}
public List<TestAidlBean> getList() throws RemoteException {
return listBean;
}
};
}
还要再AndroidManifest中注册一下,利用android:process为服务开启新的进程1
2
3
4
5
6
7
8<service
android:name=".service.TestServerService"
android:process=":remote">
<intent-filter>
<action android:name="com.zhouk.soft.mystudio.service.TestServerService"/>
<!--<action android:name="scut.carson_ho.service_server.AIDL_Service1"/>-->
</intent-filter>
</service>
在应用主进程的活动中开启进程服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56private static final String TAG = "客户端TestClientActivity";
private IMyAidlInterface ser;
private ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
ser = IMyAidlInterface.Stub.asInterface(service);
if (ser != null) {
try {
Log.e(TAG, ser.AIDL_Service());
Toast.makeText(TestClientActivity.this, ser.AIDL_Service(), Toast.LENGTH_LONG).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
public void onServiceDisconnected(ComponentName name) {
}
};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e(TAG, "开始连接其他进程的服务...");
Intent intent = new Intent("com.zhouk.soft.mystudio.service.TestServerService");
//需要通过setPackage()方法指定包名
intent.setPackage(getPackageName());
//绑定服务,传入intent和ServiceConnection对象
boolean isS = bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
Log.e(TAG, "是否连接成功:"+isS);
findViewById(R.id.btn).setOnClickListener(v -> {//往服务进程中添加Bean数据
try {
ser.addMyAidlBean(new TestAidlBean(123456, "name1"));
} catch (RemoteException e) {
e.printStackTrace();
}
});
findViewById(R.id.btn2).setOnClickListener(v -> {//获取服务进程中的List数据
if (ser != null) {
try {
for (int i = 0; i < ser.getList().size(); i++) {
Log.e(TAG, "列表数据" + i + ":--->" + ser.getList().get(i).getName());
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}结果
客户端:
服务端:
客户端:
总结
主要介绍了AIDL基于C/S的实现操作。日常开发中使用多进程的场景并不多见,但在有些地方例如音视频开发中能起到十分关键的作用,掌握基础的多进程开发知识还是十分有必要的。