说到进程间通信,一般首先就会想到
AIDL
,也看了很多文章,做下笔记,记录一下,方便以后查阅。
对于 AIDL
我是这样理解的,首先进程间是无法通信的,那要通信就得有一个媒介或者说两个进程有统一对外的接口可以相互识别,从这个 AIDL
全程的名字Android Interface Definition Language
(android 接口定义语言) 来看不难看出它就是我们进程间通信的媒介,它可以实现我们想要的通信。
在翻阅网上各类文章的讲解后,我认为一个比较好的实例可以更好理解这个东西,具体如下:
第一步
我们新创建两个module
,代表我们两个进程,进程名称默认就是我们程序的包名:
第二步
我们先编写service
这个module
里的代码,先定义一个 Person
的一个bean
对象,记住一定要implements Parcelable
接口,大致如下: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
41public class Person implements Parcelable {
private String mName;
public Person(String name) {
mName = name;
}
protected Person(Parcel in) {
mName = in.readString();
}
public static final Creator<Person> CREATOR = new Creator<Person>() {
public Person createFromParcel(Parcel in) {
return new Person(in);
}
public Person[] newArray(int size) {
return new Person[size];
}
};
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mName);
}
public String toString() {
return "\nPerson{" +
"mName='" + mName + '\'' +
'}';
}
}
然后我们再新建一个文件夹:aidl
,新建一个包名和Person
类一模一样的包名和与之对应的aidl
,还有一个我们对外提供获取person
集合的一个aidl
:
在Person.aidl
里,我们序列化我们java
里的 Person
类:
1 | package com.example.service.bean; |
IMyAidl.aidl
文件提供对外方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// IMyAidl.aidl
package com.example.service.bean;
//特别注意一定要手动导包,不会自动导包
import com.example.service.bean.Person;
// Declare any non-default types here with import statements
//可以理解为通信媒介
interface IMyAidl {
/**
* 除了基本数据类型,其他类型的参数都需要标上方向类型:in(输入), out(输出), inout(输入输出)
*/
void addPerson(in Person person);
List<Person> getPersonList();
}
然后在我们的java文件
里,新建一个MyAidlService
,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
39public class MyAidlService extends Service {
private final String TAG = this.getClass().getSimpleName();
private ArrayList<Person> mPersons;
/**
* 创建生成本地的binder ,实现AIDL的方法
*/
private IBinder mIBinder = new IMyAidl.Stub(){
public void addPerson(Person person) throws RemoteException {
mPersons.add(person);
}
public List<Person> getPersonList() throws RemoteException {
return mPersons;
}
};
/**
* 客户端与服务端绑定时的回调,返回IBinder对象后客户端就可以通过它远程调用服务端的方法,即实现了通讯
* @param intent
* @return
*/
public IBinder onBind(Intent intent) {
mPersons = new ArrayList<>();
return mIBinder;
}
public void onCreate() {
super.onCreate();
}
最后别忘了在清单文件中注册MyAidlService
1
2
3
4<service
android:name="com.example.service.MyAidlService"
android:enabled="true"
android:exported="true" />
到此,我们完成了service
端的工作:
第三步
将我们刚才创建好的aidl
文件夹拷贝到 app
module
下main
文件夹下,在MainActivity
中绑定服务,1
2
3Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.service","com.example.service.MyAidlService"));
bindService(intent,mConnection,BIND_AUTO_CREATE);
其中这个mConnection
可以让我们拿到IMyAidl
对象的代理1
2
3
4
5
6
7
8
9
10
11
12private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mAidl = IMyAidl.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mAidl = null;
}
};
通过返回的IBinder
拿到这个IMyAidl
,此时我们就可以通信了,例如我们调用IMyAidl
中的addPerso
n方法,再调用getPersonList
看看:1
2
3
4
5
6
7
8
9
10
11Random random = new Random();
Person person = new Person("qian"+random.nextInt(20));
try{
mAidl.addPerson(person);
List<Person> mPersons = mAidl.getPersonList();
tvName.setText(mPersons.toString());
}catch (Exception e){
e.printStackTrace();
}
打印发现list 返回了我们添加的Person
,完成了app
与service
两个进程间的通信。demo
地址:https://github.com/QQabby/AIDLDemo