上一节总结了下IPC的基础概念,这一节主要介绍下IPC的实现方式,下面先通过一张图来了解下IPC有哪些方式:
通过上面这张图我们可以知道,IPC方式实际上都是通过Binder来实现的,只不过封装方式不同,下面我们再通过一张表,来了解下IPC不同方式之间的区别:
通过上面这张表,我们对IPC不同方式有了个大概的了解,下面我们具体来介绍每种方式的使用。
一.Bundle
Bundle用于四大组件间的进程间通信,通过Intent.putExtra()传递Bundle数据,因为Bundle实现了Parcelable接口,所以它能很方便的在进程间传输,它不仅可以传输基本数据类型,还可以传输实现了Parcelable或Serializable接口的对象。
Intent intent = new Intent(this, PersonService.class);
Bundle bundle = new Bundle();
bundle.putString("name","张三");
bundle.putInt("age",12);
bundle.putParcelable("person",new Person("王二麻子",13));
intent.putExtra("bundle",bundle);
bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
二.文件共享
两个进程通过读/写同一个文件来交换数据,这种方式适用于对数据同步要求不高的进程之间进行通信,并且要妥善处理并发读/写的问题。另外SharedPreference是个特例,它底层基于xml实现,系统对于它的读写基于缓存,因此多进程模式下,读写变得不可靠,可能丢失数据。
三.AIDL
1.概念
android接口定义语言,如果在一个进程中要调用另外一个进程中对象的方法,可使用AIDL生成可序列化的参数,AIDL会生成一个服务端对象的代理类,客户端通过它实现间接调用服务端对象的方法。
2.支持的数据类型
- 基本数据类型:byte、int、long、float、double、boolean、char
- String类型
- CharSequence类型
- List类型,且里面的元素都能被AIDL支持
- Map类型,且里面的元素都能被AIDL支持
- 实现Parcelable接口的对象
- 所有AIDL接口本身
注意:除了基本数据类型,其它类型参数必须标上方向:in、out、inout,用于表示跨进程通信中数据的流向,具体的区别在于:
in:表示数据只能由客户端流向服务端
out:表示数据只能由服务端流向客户端
inout:表示数据可在服务端和客户端之间双向流动
3.使用步骤
(1)创建数据实体类,实现Parcelable接口
(2)创建实体类的aidl声明
(3)创建aidl接口,表示服务端对外提供的能力
(4)服务端代码的实现
(5)客户端代码的实现
4.案例解析
(1)创建Person.java实体类,实现Parcelable接口
public class Person implements Parcelable {
private String name;
private int age;
//Parcel是IBinder发送消息的容器,实现对象数据在内存中的传递
protected Person(Parcel in) {
name = in.readString();
age = in.readInt();
}
public static final Creator<Person> CREATOR = new Creator<Person>() {
@Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
public void readFromParcel(Parcel dest) {
name = dest.readString();
age = dest.readInt();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name , int age){
this.name = name;
this.age = age;
}
}
(2)创建Person类的aidl声明
// Person.aidl
package com.czy.aidldemo;
parcelable Person ;
(3)创建IPersonManager接口
// IPersonManager.aidl
package com.czy.aidldemo;
import com.czy.aidldemo.Person;
interface IPersonManager {
void addPerson(inout Person person);
List<Person> getPersonList();
}
注意:
a.实体类的包名与AIDL文件的包名必须一致。
b.IPersonManager中必须import导入所需实体类。
c.接口中声明的方法参数需要使用in/out/inout。
d.实体类和aidl文件在两端都要有,且在同一包名下。
(4)编译项目,自动生成IPersonMa