一、前序
Android的IPC方式有很多种,市面上Android开发用的比较多的方式是BroadcastReceiver(其他的共享文件之类的非实时通讯的就不要考虑了)。其实我也很好奇,为啥不用最具Android特色的Binder(即AIDL)来实现呢?
Binder相对于BroadcastReciver的方式有很多优点:
1.BroadcastReceiver效率比较低,不稳定,而且很多手机厂商会对BroadcastReceiver做限制。
2.BroadcastReceiver不是可靠连接,有可能广播发出去根本就没有回应。
个人总结大多数的IPC开源库为啥不用Binder来实现:
1.BroadcastReceiver想对于Binder来书比较简单,开发难度低,且多个进程之间不好做到统一;
2.Binder为CS架构,有服务端客户端概念,无法双向通讯(必须要有客户端主动发起请求)。
先说说针对上诉问题的解决思路:
1.怎么做好多进程之间的统一:即定义相同包名类名完全相同的AIDL接口,统一开放给客户端调用的方法;
2.针对CS架构无法实现双向通讯,为每个进程创建一个Service,即每个进程都是服务端,且每个进程同时也都可以是客户端(如果需要向其他进程请求的话)。
该文章主要为推广本人最近写的一个Android IPC的一个开源库。该库主要通过Binder的方式实现多进程间的通讯。目前支持消息传递和直接跨进程调用方法并获取返回值。
二、先上正餐,怎么使用该开源库:
1.在Project的gradle文件中添加远程仓库地址
allprojects {
repositories {
// 添加maven*仓库
mavenCentral()
}
}
2.添加依赖包并同步:
// 注解依赖包
implementation "io.github.wengliuhu:KimIpc_annotation:1.0"
// IPC库依赖包
implementation "io.github.wengliuhu:KimIpc_ipc:1.0"
// apt动态编译包
annotationProcessor "io.github.wengliuhu:KimIpc_complier:1.0"
3.添加需要交互的进程的包名(任意类上添加注解都可以,为了方便查找,可以定义一个类IpcUtil):
// "com.kim.app2"和 "com.kim.ipcapp3"是用以创建这两个包名的进程下的客户端代码,即 "com.kim.app2"和 "com.kim.ipcapp3"为服务端。
@Server(serverPackageNames = {"com.kim.app2", "com.kim.ipcapp3", "com.kim.kimipc"})
4.给开放给其他进程调用的静态方法添加注解:
// 注意:
// 1.此方法必须为静态方法,目前只支持有且只有一个string类型的参数;
// 2.如果有返回类型,必须为String类型,如无返回类型,可以写为void类型。
@IpcMethod(key = "gotoSecondActivity")
public static String gotoSecondActivity(String msg){
if (topActivity != null);
Intent intent = new Intent(topActivity, SecondActivity.class);
topActivity.startActivity(intent);
return "准备跳转第二个界面";
}
5.开始编译生成IpcManager.java类(也可以点击Make Project来生成IpcManager.java):
编译后在此目录下即可找到编译出来的IpcManager类:
6.初始化IPC:
IpcManager.getInstance().init();
7.启动需要监听的进程(此处开放给用户选择是为了可能当前界面只关注特定的进程消息):
// bindServiceForever(String packageName)为一直开启包名为packageName的进程的IPC
// bindService(Context context, String packageName)为只开启当前Activity的,后续有可能会断开连接
//此处为开启包名为IpcManager.COM_KIM_APP2(COM_KIM_APP2为注解@Server注册的包名的大写)的Service(即开启该包名所在进程的服务端)
IpcMessager.getInstance(getApplication()).bindServiceForever(IpcManager.COM_KIM_APP2);
IpcMessager.getInstance(getApplication()).bindServiceForever(IpcManager.COM_KIM_IPCAPP3);
8.发送消息:
// IpcMessager下的方法:
// 发送调用服务端注册的方法,methodName为@IpcMethod注解的key
send2Method(String methodName, String params)
// 发送给指定包名所在进程,调用该进程的注册方法
send2Method(String packageName, String methodName, String params)
// 发送消息
sendMessage(String key, String value)
// 发送给指定进程消息
sendMessage(String packageName, String key, String value)
9.监听其他进程发送的消息
IpcMessager.getInstance(getApplication()).addMessageLisenter(new IMessageLisenter() {
@Override
public void onMessage(String key, String value) {
// 此处线程是跑在Binder线程池里面的,Binder方式是异步的。如果要在主线程需要切换
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
// StringBuilder stringBuilder = new StringBuilder(receiveTv.getText());
// stringBuilder.append("接收到信息:" +value + "\n");
// receiveTv.setText(stringBuilder.toString());
// }
// });
}
});
三、简述一下原理:
每个进程都有一个IpcService作为服务端,通过@Server注解动态生成需要关注的其他进程的客户端(即ServiceConnection,存在IpcManager类里面)。初始化时把所有信息注入到IpcMessager对象中(所有的开启服务、发送消息和接收消息都有该类负责)。
四、最后
附上项目源码地址:KimIpc