1、进程间通信
在Android应用开发里面,一般的APP都使用不到多进程开发,但一般来说,我们也接触过多进程相关的东西,比如说我们使用第三方推送的时候,这里的推送服务都是属于远程服务,APP并没有启动的时候,也会得到推送的消息。
进程间通信,也是比较模糊的概念,一直以来也不好理解,为什么进程间通信还要搞得那么复杂,当然这还得源于Android系统的安全性来考虑。
2、进程间通信的方式
进程间通信的方式比较多,Bundle、ContentProvider、AIDL、Messanger、共享文件、Socket等等。
AIDL是官方支持的,多进程、多线程,支持并发的进程间通信方式。也是本次要记录的IPC方式。另外,Messanger只支持单线程的进程间通信(内部也是通过AIDL实现)。
3、AIDL相关的知识点
通常说的进程间通信主要是指:Activity与远程服务Service的数据交互。那么这里涉及到几个知识点
1、Activity,如何绑定Service,在绑定的过程中如何拿到AIDL接口实现接口调用。
2、Service,AIDL接口的实现,在绑定成功之后,返回Binder引用到客户端。
3、Binder,进程间通信的桥梁,不同进程之间通信的提供协议。
4、AIDL,接口描述语言,描述接口,跟Java接口不同,不能定义变量,只可以定义方法。
5、传递对象,AIDL接口传参只允许传递基本数据类型,传递对象需要通过实现Parcelable接口。
6、Parcelable,对象想要实现进程间通信,就要实现Parcelable接口,才可以序列化后进行传递。
4、客户端如何发送消息给服务器端
4.1、定义AIDL接口
package com.example.aidl;
import com.example.aidl.data.CustomData;
import com.example.aidl.CustomReceiver;
interface CustomSender {
void sendMessage(in CustomData customData);
void register(CustomReceiver receiver);
void unRegister(CustomReceiver receiver);
}
4.2、Activity首先绑定服务Service
private void startBindService() {
Intent intent = new Intent(this, CustomService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
4.3、在Service服务返回IBinder,Binder sender也需要在服务器端实现
@Override
public IBinder onBind(Intent intent) {
return sender;
}
private IBinder sender = new CustomSender.Stub() {
@Override
public void sendMessage(CustomData customData) throws RemoteException {
if (customData == null) {
Log.i(TAG, "消息是空的");
} else {
String name = customData.getName();
int id = customData.getId();
Log.i(TAG, "收到客户端的消息:" + name + " " + id);
}
}
};
4.4、Activity绑定Service成功之后,通过返回来的IBinder,转换成为接口,从而实现了接口的调用
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
CustomData data = new CustomData();
data.setName("我的消息");
data.setId(6);
try {
customSender = CustomSender.Stub.asInterface(service);
customSender.sendMessage(data);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
5、服务的如何推送消息至客户端
5.1、Activity实现消息接收器的AIDL接口
//消息监听回调接口
private CustomReceiver customReceiver = new CustomReceiver.Stub() {
@Override
public void onMessageReceived(String message) throws RemoteException {
Log.i(TAG, "onMessageReceived: " + message);
}
};
5.2、在服务器连接成功的时候,需要注册,有点像是观察者模式。
customSender.register(customReceiver);
5.3、服务端实现的接口方法
/**
* 用于处理消息监听的类
**/
private RemoteCallbackList<CustomReceiver> listenerList = new RemoteCallbackList<>();
private IBinder sender = new CustomSender.Stub() {
@Override
public void register(CustomReceiver receiver) throws RemoteException {
if (receiver != null) {
listenerList.register(receiver);
}
}
@Override
public void unRegister(CustomReceiver receiver) throws RemoteException {
if (receiver != null) {
listenerList.unregister(receiver);
}
}
};
5.4、通常服务端会有一个线程与后台发生长连接,获取到数据之后,要通过遍历消息监听器列表,从而实现来此客户端的AIDL接口调用,这里模拟每3秒给客户端发送消息
private class MessageRunnable implements Runnable {
@Override
public void run() {
while (!isDestroy.get()) {
Log.i(TAG, "线程启动!");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
int size = listenerList.beginBroadcast();
for (int i = 0; i < size; i++) {
CustomReceiver customReceiver = listenerList.getBroadcastItem(i);
if (customReceiver != null) {
customReceiver.onMessageReceive("来自服务器端的消息。时间:" + System.currentTimeMillis());
}
}
listenerList.finishBroadcast();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
6、重连机制 DeathRecipient
6.1、实现DeathRecipient,监测服务死亡的情况,比如服务Service挂掉了,这个时候应该重启服务
private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (customSender != null) {
customSender.asBinder().unlinkToDeath(this, 0);
customSender = null;
}
startBindService();
}
};
6.2、在连接上的时候添加上
customSender.asBinder().linkToDeath(deathRecipient, 0);
7、如何做进程校验(初始化application,进程id,权限)
多进程会出现实现多个Application的情况,通常,我们Application里面的初始化却并不需要多次初始化,所以在Application的初始化onCreate()方法里面可以进行分进程而初始化,而区别进程的方法可以根据进程名称来实现。然后判断名称来实现相关的初始化。
private String getProcessName() {
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> list = activityManager.getRunningAppProcesses();
if (list == null) {
return null;
}
for (ActivityManager.RunningAppProcessInfo runningAppProcessInfo : list) {
if (runningAppProcessInfo != null && runningAppProcessInfo.pid == Process.myPid()) {
return runningAppProcessInfo.processName;
}
}
return null;
}
8、总结
进程间通信用的得当会变得相当强大,比如多个进程获得系统分配的内存也更大,可以实现的事件也更多,可以做的事情也是非常值得思考的,但使用不当,就只会给自己增加工作量,人还是要往前进步的,多一份知识多一条路。