什么是IPC
IPC是Inter-Process Communication的缩写,含义为进程间通信或者跨进程通信,是指两个进程之间进行数据交互的过程。
- 线程是CPU调度的最小单元,同时线程是一种有限的系统资源
- 进程一般指一个执行单元,在PC和移动设备上指一个程序或者一个应用
- 一个进程可以包含多个线程
- 最简单的情况下,一个进程中只有一个线程,即主线程,在android中主线程也叫UI线程
- 很多时候,一个进程中需要执行大量的耗时任务,如果这种这些任务都放在主线程中去执行就会造成界面无响应,也就是我们android中所说的ANR(Application Not Responding),即应用无响应。解决这个问题就是把一些耗时操作放到子线程中
Serializable接口与Parcelable接口
- Serializable接口是Java所提供的一个序列号接口,它是一个空接口,为对象提供标准的序列化与反序列化操作。使用该接口比较简单,只要你对应的类实现该接口即可
- Parcelable是Android提供的一种新的序列化方式,它实现接口后需要重新几个对应的方法
- 两者区别:Serializable是Java中的序列化几口,使用简单但开销很大,序列化与反序列化过程需要大量I/O操作。Parcelable是Android推荐的序列化方式,但使用稍微麻烦一些,但效率高一些,Parcelable主要用在内存序列化上。(本人实际开发中其实还是Serializable用的多一些,使用简单,)
Binder
Binder是Android中的一个类,它实现了IBinder接口。从IPC角度来说,Binder是Android中一种跨进程通信的方式。从Android Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager,等等)和相应ManagerService的桥梁。从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含了服务单业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。在Android开发中,Binder主要用在Service中,包括AIDL和Messenger,其中普通的Service中的Binder不涉及进程间通信,而Messenger的底层其实是AIDL。
Android中的IPC方式
- 使用Bundle
四大组件中的三大组件(Activity,Service,Receiver)都支持Intent中传递Bundle数据 - 使用文件共享
只适用于数据同步要求不高的进程间的通信,不推荐 - 使用Messenger
- 服务端进程
首先,我们需要在服务端创建一个Service来处理客户端的连接请求,同时创建一个Handler并通过它来创建一个Messenger对象,然后在Service的onBind中返回这个Messenger对象底层的Binder,当然当服务端接受到客户端发送消息有时我们还需要回应客户端,比如回复下面示例代码中的“嗯,你的消息我已经收到,稍后会回复你。”(注:注册下面的service,让其运行在单独的进程中,
android:name=".messenger.MessengerService" )
android:process=":remote" >
- 服务端进程
public class MessengerService extends Service {
private static final String TAG = "MessengerService";
private static class MessengerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyConstants.MSG_FROM_CLIENT:
Log.i(TAG, "receive msg from Client:" + msg.getData().getString("msg"));
Messenger client = msg.replyTo;
Message relpyMessage = Message.obtain(null, MyConstants.MSG_FROM_SERVICE);
Bundle bundle = new Bundle();
bundle.putString("reply", "嗯,你的消息我已经收到,稍后会回复你。");
relpyMessage.setData(bundle);
try {
client.send(relpyMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
}
private final Messenger mMessenger = new Messenger(new MessengerHandler());
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
}
- 客户端进程
客户端进程中,首先要绑定服务端的Service,绑定成功后用服务端返回的IBinder对象创建一个Messenger,通过这个Messenger就可以向服务端发送消息,发消息类型为Message对象。如果需要服务端能够回应客户端,就和服务端一样,我们还需要创建一个Handler并创建一个新的Messenger,并把这个Messenger对象通过Message的replyTo参数传递给服务端,服务端通过对这个replyTo参数就可以回应客户端。当然,客户端也可以准备一个接受消息的Messenger和handler
public class MessengerActivity extends Activity {
private static final String TAG = "MessengerActivity";
private Messenger mService;
private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler());
private static class MessengerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyConstants.MSG_FROM_SERVICE:
Log.i(TAG, "receive msg from Service:" + msg.getData().getString("reply"));
break;
default:
super.handleMessage(msg);
}
}
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger(service);
Log.d(TAG, "bind service");
Message msg = Message.obtain(null, MyConstants.MSG_FROM_CLIENT);
Bundle data = new Bundle();
data.putString("msg", "hello, this is client.");
msg.setData(data);
msg.replyTo = mGetReplyMessenger;
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName className) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger);
Intent intent = new Intent("com.ryg.MessengerService.launch");
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
}
}
- 使用AIDL
Messenger是以串行的方式处理客户端发来的消息,如果大量的消息同时发到服务端,服务端仍然只能一个个处理,如果有大量的并发请求,那么用Messenger就不再适用。同时,Messenger的作用主要是为了传递消息很多时候我们可能需要跨进程调用服务端的方法,这时我们就可以使用AIDL。- 服务端
服务端首先要创建一个Service用来监听客户端的连接请求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明,最后在Service中实现这个AIDL接口即可 - 客户端
绑定服务端的Service,绑定成功后将服务端返回的Binder对象转成AIDL接口所属的类型,接着就可以调用AIDL中的方法了
- 服务端
其实AIDL的调用比较简单,此处略去相关代码。但需要注意的是为了程序的健壮性,我们需要考虑到Binder是有可能意外死亡的,这往往是由于服务端进程意外停止了,这时我们需要重新连接服务。常见的有两种方法,一种是给Binder设置DeathRecipient监听,当Binder死亡时,我们会收到binderDied方法的回调,在binderDied方法中我们可以重连远程服务。另一种方法是在onServiceDisconnected中重连远程服务。
- 如何给Binder设置死亡代理
1. 声明一个DeathRecipient对象。DeathRecipient是一个接口,其内部只有一个方法binderDied,我们需要实现这个方法
,当Binder死亡的时候,系统就会回调 BinderDied 方法,然后我们就可以移出之前的binder代理并重新绑定远程服务
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (mRemoteBookManager == null)
return;
mRemoteBookManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
mRemoteBookManager = null;
// TODO:这里重新绑定远程Service
}
};
2. 在客户端绑定远程服务成功后,给binder设置死亡代理
mService = ...Manager.Stub.asInterface(binder);
binder.linkToDeath(mDeathRecipient ,0);
- 使用ContentProvider
一般用于一对多的数据共享,由于篇幅原因,该处不做详细介绍,实际开发中感觉可能用的不是特别多 - 使用Socket
Socket也称为“套接字”,是网络通信中的概念。它分为流式套接字和用户数据报套接字两种,分别对应于网络的传输控制层的TCP和UDP协议。TCP协议是面向连接的协议,提供稳定的双向通信功能,TCP连接的建立需要经过“三次握手”才能完成,为了提供稳定的数据传输功能,其本身提供了超时重传机制,因为具有很高的稳定性;而UDP是无连接的,提供不稳定的单向通信功能,当然UDP也可以实现双向通信功能。在性能上,UDP具有更好的效率,缺点就是不能保证数据传输的正确性,尤其是在网络拥堵的情况下。