开发艺术之旅 | IPC机制
经常会听到AIDL、Binder机制,但是其实很多时候用不到(可能只是我用得少hhh),有时间来总结下吧,先看一些名词:
- IPC(Inter—Process Communication) 跨进程通信
- AIDL( Android Interface Definition Language),Android接口定义语言,是用于定义服务器和客户端通信接口的一种描述语言。
- RPC (Remote Procedure Call) 远程调用
推荐参考:厘米姑娘的学习笔记
基础
使用多进程模式
- Android使用多进程的方法只有一个:在AndroidManifest文件中给四大组件指定android:progress属性
- 多进程会遇到的问题
- 静态成员和单例模式完全失效
- 线程同步机制失效
- SharePreferences 可靠性下降
- Application多次创建
序列化传输数据
- Serializable 接口
- Parcelable 接口
Serializable
- 直接实现这个接口,系统自动实现,属于java1的接口,但是效率相对较低
Parcelable
- 实现这个接口,实现这个接口后会需要我们实现几个方法,一般只要进行读取、写入这个两个方法就可以了
public class User implements Parcelable {
public int userId;
public String userName;
public boolean isMale;
public User(int userId, String userName, boolean isMale) {
this.userId = userId;
this.userName = userName;
this.isMale = isMale;
}
// 快捷生成的构造函数,在这读取函数
protected User(Parcel in) {
userId = in.readInt();
userName = in.readString();
isMale = in.readInt() == 1;
}
// 自动生成 不必修改
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
// 自动生成 除非存在 文件描述符 需要返回 1 否则不必修改
@Override
public int describeContents() {
return 0;
}
// 需要实现这个方法,把参数写入
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(userId);
dest.writeString(userName);
dest.writeInt(isMale ? 1 : 0);
}
}
Binder
几个角度简单理解
- 是Android中的一个类,实现了IBinder接口
- 是Android中一种跨进程通信方式
- 从Android Framework来看,是ServiceManager连接各种Manager的桥梁
- 从Android 应用层来看,是服务端和客户端进行通信的媒介(bindService会返回)
使用AIDL文件
新建两个文件
// User.aidl
package com.wj.aidltest;
parcelable User;
**********************************
// IUserManager.aidl
package com.wj.aidltest;
import com.wj.aidltest.User; // 需要手动import
interface IUserManager {
List<User> getUserList();
void addUser(in User user);
}
之后AS就会为我们生成IUserManager文件了,通过这个文件可以帮助我们理解Binder机制,这个生成的文件在
app\build\generated\aidl_source_output_dir\debug\compileDebugAidl\out\com\wj\aidltest\IUserManager.java
了解AIDL
AIDL文件其实是可以帮我们快速生成Binder代码的工具,常用到方法和需要了解的类:例如一个IUserManager.aidl文件,生成的相关类、方法
- IUserManager:是一个继承 android.os.IInterface 的接口,包含我们定义的方法
- Stub类:Binder对象实现类,服务端返回给客户端调用
- Stub.Proxy:Binder对象的代理类,如果是跨进程调用会返回代理类
- Stub.asBinder:返回Binder类本身
- Stub.asInterface:客户端调用,将Binder类转换成客户端需要的AIDL接口
- Stub.onTransact():当客户端发起跨进程请求时,经过层层封装最后会走到这个方法,运行在Binder线程池中
- Stub.transact():IBinder接口方法,跨进程调用时Stub.Proxy会调用此方法,客户端线程挂起,知道服务端
onTransact方法返回结果
IUserManager.java 结构
内部包含了我们定义的两个方法以及 一个继承Binder并且实现了这个接口的Stub抽象类,主要逻辑都在Stub这个类,Stub这个类又包含了一个Proxy类
public interface IUserManager extends android.os.IInterface{
public static abstract class Stub extends android.os.Binder implements com.wj.aidltest.IUserManager{
...
}
// 待实现
public java.util.List<com.wj.aidltest.User> getUserList() throws android.os.RemoteException;
// 待实现
public void addUser(com.wj.aidltest.User user) throws android.os.RemoteException;
}
Stub类
Stub 类实现了IUserManager 接口,分析如下
分析以 getUserList 方法为例
public static abstract class Stub extends android.os.Binder implements com.wj.aidltest.IUserManager{
// 标识 为完整类名
private static final java.lang.String DESCRIPTOR = "com.wj.aidltest.IUserManager";
// 定义两个标识,用于判断是哪个方法
static final int TRANSACTION_getUserList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
/** Construct the stub at attach it to the interface. */
// 构造函数 连接到接口
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
// 将Binder对象转换成客户端所需要的AIDL接口类型对象,具体逻辑如下
public static com.wj.aidltest.IUserManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
// 获取
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
// 如果是本地进程,返回本身
if (((iin!=null)&&(iin instanceof com.wj.aidltest.IUserManager))) {
return ((com.wj.aidltest.IUserManager)iin);
}
// 如果不是本地进程,返回Stub内部的一个代理类,具体见下面
return new com.wj.aidltest.IUserManager.Stub.Proxy(obj);
}
// 获取Binder对象,返回本身
@Override public android.os.IBinder asBinder()
{
return this;
}
// 跨进程调用会走到这个方法
// 1、 code 判断是那个方法
// 2、 data 取出需要的参数
// 3、 reply 存储方法返回结果 在proxy类会读取
// return : 如果为false 客户端请求会失败
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
java.lang.String descriptor = DESCRIPTOR;
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
case TRANSACTION_getUserList:
{
data.enforceInterface(descriptor);
// 调用本地的getUserList方法
java.util.List<com.wj.aidltest.User> _result = this.getUserList();
reply.writeNoException();
// 将结果写入,
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addUser:
{
data.enforceInterface(descriptor);
com.wj.aidltest.User _arg0;
if ((0!=data.readInt())) {
_arg0 = com.wj.aidltest.User.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addUser(_arg0);
reply.writeNoException();
return true;
}
default:
return super.onTransact(code, data, reply, flags);
}
}
// onTransact end //
}
Stub.Proxy 类
远程进程调用会返回这个对象
分析以 getUserList 方法为例
private static class Proxy implements com.wj.aidltest.IUserManager
{
private android.os.IBinder mRemote;
// 传入 IBinder对象
Proxy(android.os.IBinder remote){
mRemote = remote;
}
@Override public android.os.IBinder asBinder(){
return mRemote;
}
public java.lang.String getInterfaceDescriptor(){
return DESCRIPTOR;
}
// 跨进程调用方法:
@Override public java.util.List<com.wj.aidltest.User> getUserList() throws android.os.RemoteException{
// 创建data用于存储参数
// 创建reply 传给Stub类,Stub的onTransact写入结果后再读出
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.wj.aidltest.User> _result;
try {
// 写入标识
_data.writeInterfaceToken(DESCRIPTOR);
// 调用Stub的transact方法,传入定义好的标识、参数、用于接收结果的Parcel
boolean _status = mRemote.transact(Stub.TRANSACTION_getUserList, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getUserList();
}
_reply.readException();
// 从reply读取结果
_result = _reply.createTypedArrayList(com.wj.aidltest.User.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
// 返回结果
return _result;
}
@Override public void addUser(com.wj.aidltest.User user) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((user!=null)) {
_data.writeInt(1);
user.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
boolean _status = mRemote.transact(Stub.TRANSACTION_addUser, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().addUser(user);
return;
}
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
public static com.wj.aidltest.IUserManager sDefaultImpl;
}
小结
Q:为什么Binder需要使用AIDL等机制?
- AIDL 是Android帮助我们实现跨进程通信的一个工具,不用AIDL我们也可以实现相关功能,但是AIDL可以帮我们生成相关代码
- 注意在 Stub的asInterface 方法,如果是本地进程,会返回一个Stub对象本身;如果不是同一进程,就会返回一个Stub.Proxy 对象,进而导致我们在ServiceConnection的onServiceConnected接收到的IBinder对象其实是一个BinderProxy对象,而不是我们定义的Binder,所以直接转换成接口的时候会保存,此时需要用到Stub.asInterface,返回一个代理类Stub.Proxy类
Q:Stub.Proxy 如何实现跨进程调用?
- Stub.Proxy 实现了我们定义的接口,但是他的实现方法是,通过调用Stub的transact方法,传入需要的参数、一个用于接收返回值的Parcel以及方法标识,最后Stub回调到onTransact方法。
- 在onTransact方法会取出参数,调用Stub相应的方法,再把结果写入传入的Parcel;
- 在onTransact执行完方法后,在Stub.Proxy相应的方法会取出结果并返回
流程图
Android几种IPC机制
- Bundle 启动另一个进程的Activity、Service、Receiver,可以在Bundle中富家我们需要传输给远程的信息
- 使用文件共享,通过文件为媒介,传输信息(不推荐使用SharePreferences)
- 使用Messenger
- 使用AIDL
- socket通信
重点是Messenger 和 AIDL
Messenger
底层也是基于AIDL ,可以简单的进行进程间通信,但是它一次只能处理一次请求,类似串行通信,所以不必考虑并发的问题,也不适合大量的并发请求
使用
在服务端
- 新建一个远程服务
- 新建一个Handler,用于处理从客户端发过来的消息
- 新建一个Messenger,把第二步构建的Handler传入
- 在onBind方法,返回Messenger.getBinder()
- 如果需要实现服务端向客户端发送消息,从 Message.replyTo 获取客户端的 Messenger,通过这个Messenger发送消息
public class MessengerService extends Service {
// 2. 新建一个Messenger 构造函数传入下面构建的Handler
private final Messenger mMessenger = new Messenger(new MessengerHandler());
public MessengerService() {
}
@Override
public IBinder onBind(Intent intent) {
// 3. 返回mMessenger.getBinder 的Binder对象
return mMessenger.getBinder();
}
// 1. 新建一个Handler处理信息
private static class MessengerHandler extends Handler{
private String TAG = "MessengerHandler";
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what){
case 1:
// 打印收到的信息
Log.d(TAG, "rec from client: "+ msg.getData().getString("data"));
// 获取客户端传过来的 Messenger 用于 给客户端发送消息
Messenger client = msg.replyTo;
Message replyMsg = Message.obtain();
replyMsg.what = 2;
Bundle data = new Bundle();
data.putString("reply","i have receive you msg");
replyMsg.setData(data);
try {
// 发送消息
client.send(replyMsg);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
}
}
客户端
- 新建一个ServiceConnection,在onServiceConnected中初始化一个Messenger 【Messenger mService = new Messenger(IBinder);】
- 通过第一步创建的Messenger,就可以向服务端发送消息了
- 如果需要接收服务端发送过来的消息,需要新建一个客户端自己的Messenger,并传入一个客户端自己的Handler 处理服务端传过来的消息,并且在发送消息给 服务端时,在message的reply字段将这个Messenger赋值
4.bindService 开始通信
具体如下
public class MainActivity extends AppCompatActivity {
private TextView textView;
public String TAG = "MainActivity";
// 通过服务端返回的IBinder构建的Messenger 用于给服务端发消息
private Messenger mService;
private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.main_tv);
textView.setOnClickListener(v -> {
// 一个简单的监听,绑定服务
Intent intent = new Intent(this,MessengerService.class);
bindService(intent,connection,BIND_AUTO_CREATE);
});
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 通过返回的IBinder 构建给服务端发消息的Messenger
mService = new android.os.Messenger(service);
Message msg = Message.obtain();
msg.what = 1;
Bundle data = new Bundle();
data.putString("data","Hello,this is msg from client");
msg.setData(data);
// 重点:实现双向通信,需要在这个字段将客户端定义的Messenger传过去
msg.replyTo = mGetReplyMessenger;
try {
// 发送消息
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
// 用于处理服务端发送过来的消息,这里简单打印一下
private static class MessengerHandler extends Handler{
private String TAG = "MessengerHandler";
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what){
case 2:
Log.d(TAG, "handleMessage: " + msg.getData().getString("reply"));
break;
}
}
}
}
结果实例
两个进程
客户端:
服务端:
进程ID是不一样的
流程图
AIDL
相对于Messenger,AIDL适合大量并发请求的情况,同时Messenger适用于服务端和客户端发送消息,并不能调用服务端的方法,如果需要调用服务端的方法(RPC),还是需要用到AIDL
注意点:
- 服务端和客户端的自定义bean类和aidl文件需要在相同的包下
- 服务端的Service必须是可以被外部调用的
- 调用的线程会被挂起,如果服务端是耗时操作需要在子线程,否则会导致ANR
- 调用的方法(服务端调用客户端或者客户端调用服务端)运行在Binder线程池,如果有相关的监听、回调也是在子线程(不能操作UI)
属性 | 默认值 | 含义 |
---|---|---|
android:enabled | boolean 默认为true | 是否能被系统实例化 |
android:exported | boolean 默认为true | 是否能被其他应用组件调用 |
android:permission | String 无 | 需要的权限,可以自定义 |
android:process | String 无 | 指定进程名称 |
- AIDL支持的数据类型
- 基本的数据类型
- String 和 CharSequence
- 只支持ArrayList,并且里面的元素要被AIDL支持
- 只支持HashMap,并且里面的元素要被AIDL支持
- Parcelable 所有实现了Parcelable 的对象
- AIDL 接口
- 自定义的Parcelable 需要显示的import进来,并且新建一个同名的AIDL文件声明它为Parcelable
使用
服务端
- 创建AIDL接口
- 创建远程服务
- 实现接口
- 创建AIDL接口
// IUserManager.aidl
import com.wj.aidlremote.User;
interface IUserManager {
List<User> getUserList();
void addUser(in User user);
}
// User.aidl
package com.wj.aidlremote;
parcelable User;
- 创建远程服务
public class AIDLService extends Service {
private CopyOnWriteArrayList<User> mUserList = new CopyOnWriteArrayList<>();
private String TAG = "AIDLService";
public AIDLService() {
}
@Override
public void onCreate() {
super.onCreate();
mUserList.add(new User(1,"one",true));
mUserList.add(new User(2,"two",false));
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private Binder mBinder = new IUserManager.Stub() {
@Override
public List<User> getUserList() throws RemoteException {
return mUserList;
}
@Override
public void addUser(User user) throws RemoteException {
mUserList.add(user);
Log.d(TAG, "addUser,size : " + mUserList.size());
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
return super.onTransact(code, data, reply, flags);
}
};
}
// AndroidManifest
<service
android:name=".AIDLService"
android:enabled="true"
android:exported="true"
android:process=":aidl.remote">
</service>
客户端
// 调用其他应用的服务,第一个为包名 第二个为类名全路径
Intent intent = new Intent();
intent.setComponent(new ComponentName(
"com.wj.aidlremote",
"com.wj.aidlremote.AIDLService"
));
bindService(intent,mServiceConnection,BIND_AUTO_CREATE);
// ServiceConnection
private IUserManager iUserManager;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 转化为接口实例
iUserManager = IUserManager.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
设置死亡代理
在远程服务“挂”了的时候,可以进行重新连接
// 在连接到服务时设置代理
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iUserManager = IUserManager.Stub.asInterface(service);
try {
service.linkToDeath(mDeathRecipient,0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
// 也可以在这里重新连接服务,不同点在于 这个方法在客户端的UI线程,
// binderDied在客户端的Binder线程池
}
};
// 新建一个DeathRecipient 对象
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (iUserManager == null) return;
// 先解除监听
iUserManager.asBinder().unlinkToDeath(mDeathRecipient,0);
iUserManager = null;
// 重新绑定服务
Intent intent = new Intent();
intent.setComponent(new ComponentName(
"com.wj.aidlremote",
"com.wj.aidlremote.AIDLService"
));
bindService(intent,mServiceConnection,BIND_AUTO_CREATE);
}
};
设置、移除监听
如果想给服务设定一个监听,比如当服务端添加了一个新用户的时候,就回调到客户端,可以给服务端设定一个监听
// 1. 定义一个aidl接口
// IOnNewUserAddListener.aidl
package com.wj.aidlremote;
import com.wj.aidlremote.User;
interface IOnNewUserAddListener {
void onNewUserAdded(in User user);
}
// 2. 修改原有的aidl接口
// IUserManager.aidl
import com.wj.aidlremote.User;
import com.wj.aidlremote.IOnNewUserAddListener;
interface IUserManager {
List<User> getUserList();
void addUser(in User user);
void registerListListener(IOnNewUserAddListener listener);
void unregisterListListener(IOnNewUserAddListener listener);
}
// 3. 修改Binder实现
// ** 注意 监听器需要用到 RemoteCallbackList 否则无法移除监听(传输后对象不同,无法找到对象)
private RemoteCallbackList<IOnNewUserAddListener> mListeners = new RemoteCallbackList<>();
private Binder mBinder = new IUserManager.Stub() {
@Override
public List<User> getUserList() throws RemoteException {
return mUserList;
}
@Override
public void addUser(User user) throws RemoteException {
mUserList.add(user);
Log.d(TAG, "addUser,size : " + mUserList.size());
// 遍历必须通过以下方式:
int N = mListeners.beginBroadcast();
for (int i = 0;i < N;i++){
IOnNewUserAddListener listener = mListeners.getBroadcastItem(i);
if (listener != null){
listener.onNewUserAdded(user);
}
}
// beginBroadcast 必须和finishBroadcast 成对使用
mListeners.finishBroadcast();
}
// 注册监听
@Override
public void registerListListener(IOnNewUserAddListener listener) throws RemoteException {
mListeners.register(listener);
}
// 解除注册
@Override
public void unregisterListListener(IOnNewUserAddListener listener) throws RemoteException {
mListeners.unregister(listener);
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
return super.onTransact(code, data, reply, flags);
}
};
// 4. 在客户端设置监听
private IOnNewUserAddListener.Stub iOnNewUserAddListener = new IOnNewUserAddListener.Stub() {
@Override
public void onNewUserAdded(User user) throws RemoteException {
...
//进行操作 但是注意这里是Binde线程池的线程,如果需要操作UI可以搭配Handler使用
}
};
// 注册监听
iUserManager.registerListListener(iOnNewUserAddListener);
权限配置
服务端
- 定义权限
- 在 Binder的onTransact进行权限判断
// Android Manifest
<permission
android:name="com.hjl.aidl.AIDL_SERVICE_PERMISSION"
android:protectionLevel="normal"/>
// Binder onTransact 进行权限判断(AIDL远程调用时才会用到)
...
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
// 权限判断
int check = checkCallingPermission("com.hjl.aidl.AIDL_SERVICE_PERMISSION");
if (check == PackageManager.PERMISSION_DENIED){
return false;
}
// 包名校验
String packageName = null;
String[] packages = getPackageManager().getPackagesForUid(getCallingUid());
if(packages != null && packages.length > 0){
packageName = packages[0];
}
if(!packageName.startsWith("com.wj")){
return false;
}
return super.onTransact(code, data, reply, flags);
}
...
客户端
添加权限
<uses-permission android:name="com.hjl.aidl.AIDL_SERVICE_PERMISSION"/>
Socket通信
注意事项:
- 声明权限
- 不能在主线程中访问网络
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Socket两种使用方式:TCP / UDP
- 流套接字:基于TCP协议,采用流的方式提供可靠的字节流服务。
- 数据报套接字:基于UDP协议,采用数据报文提供数据打包发送的服务。
使用步骤
客户端:
- 创建Socket对象,传入服务端地址、端口
- 等到连接成功,可以发送/接收消息
- 断开连接,关闭Socket
服务端:
- 创建Socket实例,监听端口
- 监听到连接,创建Socket对象,并通过Socket对象进行 发送/接收
- 断开连接,关闭输入输出流、Socket
ServerSocket serverSocket = new ServerSocket(8688);
Binder连接池
在使用AIDL的时候,如果每一个业务接口都要启动一个远程服务,是非常耗费资源&低效的,所以有了Binder连接池这个概念
使用步骤
- 创建多个AIDL业务接口,以及他们的实现类(客户端&服务端);创建IBinderPool AIDL接口
- 创建BinderPool类(包装连接服务、死亡代理等)、IBinderPool的实现类BinderPoolImpl,在BinderPoolImpl实现根据code返回对应的Binder
- 创建BinderPoolService,onBind返回BinderPoolImpl对象
- 客户端:实例化BindPool对象,并通过这个对象查找到相应的Binder对象,再通过这个Binder转换成对应的接口,就可以调用相应的方法了
服务端&客户端 BinderPool 代码
public class BinderPool {
private static final String TAG = "BinderPool";
public static final int BINDER_CODE = 1;
public static final int BINDER_ADD = 2; // 接口标志位
public static final int BINDER_MINUS = 3; // 接口标志位
private Context mContext;
private IBinderPool mBinderPool; // IBinderPool 接口
private static volatile BinderPool sInstance; // 单例模式
// 将异步转成同步
private CountDownLatch mConnectBinderPoolCountDownLatch;
private BinderPool(Context context){
mContext = context.getApplicationContext();
connectBinderPoolService();
}
// 单例模式
public static BinderPool getInstance(Context context){
if (sInstance == null){
synchronized (BinderPool.class){
if (sInstance == null){
sInstance = new BinderPool(context);
}
}
}
return sInstance;
}
private synchronized void connectBinderPoolService(){
mConnectBinderPoolCountDownLatch = new CountDownLatch(1);
// 绑定远程服务
Intent service = new Intent();
service.setComponent(new ComponentName(
"com.wj.aidlremote",
"com.wj.aidlremote.BinderPoolService"
));
mContext.bindService(service,mBinderPoolConnection,Context.BIND_AUTO_CREATE);
try {
// 线程挂起,等到连接时唤醒
mConnectBinderPoolCountDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private ServiceConnection mBinderPoolConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 获取IBinderPool接口对象
mBinderPool = IBinderPool.Stub.asInterface(service);
try {
// 设置死亡代理
mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient,0);
} catch (RemoteException e) {
e.printStackTrace();
}
mConnectBinderPoolCountDownLatch.countDown(); // 唤醒线程
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
/**
* 包装IBinderPool 供外部调用
* @param binderCode
* @return
*/
public IBinder queryBinder(int binderCode){
IBinder binder = null;
if (mBinderPool != null){
try {
binder = mBinderPool.queryBinder(binderCode);
} catch (RemoteException e) {
e.printStackTrace();
}
}
return binder;
}
// 为服务设置的死亡代理
private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
Log.w(TAG, "binder Died");
mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient,0);
mBinderPool = null;
connectBinderPoolService();
}
};
// IBinderPool的实现类,根据binderCode返回对应的IBinder
public static class BinderPoolImpl extends IBinderPool.Stub{
IBinder binder = null;
@Override
public IBinder queryBinder(int binderCode) throws RemoteException {
IBinder binder = null;
switch (binderCode){
case BINDER_ADD:
// IComputeImpl为ICompute的实现类
binder = new IComputeImpl();
break;
case BINDER_MINUS:
// IMinusImpl为IMinus的实现类
binder = new IMinusImpl();
case BINDER_CODE:
// binder = new ExampleImel();
break;
default:
break;
}
return binder;
}
}
}
服务端 BinderPoolService:
public class BinderPoolService extends Service {
private static final String TAG = "BinderPoolService";
private Binder mBinderPool = new BinderPool.BinderPoolImpl();
public BinderPoolService() {
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return mBinderPool; // BinderPool.BinderPoolImpl()实例
}
}
客户端:
...
// 子线程实例化、连接远程服务
new Thread(){
@Override
public void run() {
pool = BinderPool.getInstance(MainActivity.this);
}
}.start();
// 根据code 获取业务接口,进行接口调用
IBinder binder = pool.queryBinder(BinderPool.BINDER_ADD);
ICompute iCompute = IComputeImpl.asInterface(binder);
try {
int res = iCompute.add(1,1);
} catch (RemoteException e) {
e.printStackTrace();
}
IPC机制比较
名称 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
Bundle | 简单易用 | 只能传输Bundle支持的数据类型 | 四大组件间的进程间通信 |
文件共享 | 简单易用 | 不适合高并发场景,并且无法做到进程间的即时通信 | 无并发访问情形,交换简单的数据实时性不高的场景 |
AIDL | 功能强大,支持一对多并发通信,支持实时通信 | 使用稍复杂需要处理好线程同步 | 一对多通信且有RPC需求 |
Messenger | 功能一般,支持一对多串行通信,支持实时通信 | 不能很好处理高并发情形不支持RPC,数据通过Message进行传输,因此只能传输Bundle支持的数据类型 | 低并发的一对多即时通信,无RPC需求,或者无需返回结果的RPC需求 |
ContentProvider | 在数据源访问方面功能强大,支持一对多并发数据共享,可通过Call方法扩展其他操作 | 可以理解为受约束的AIDL,主要提供数据源的CRUD操作 | 一对多的进程间的数据共享 |
Socket | 功能强大,可以通过网络传输字节流,支持一对多并发实时通信 | 实现细节稍微有点繁琐,不支持直接的RPC | 网络数据交换 |