android开发中难免会遇到要求开发多进程的应用程序。在使用中总是缺少总结,以至于在遇到问题时只能依赖于google之类的。最近看了任玉刚老师的《Android开发艺术探索》这本书,第二章就讲到了多进程的通信方式,比较全面。那么我也对学过的东西总结一下吧。
1.使用Bundle
android 在启动activity ,service,receiver时可以用Bundle实现进程间的通信,同过Intent为载体。这是进程间通信最简单的一种方式了。
Intent intent = new Intent(this,BookManagerService.class);
Bundle bundle = new Bundle();
bundle.putString("bundle","hello ipc");
intent.putExtras(bundle);
bindService(intent,mConnection,BIND_AUTO_CREATE);
接着在BookManagerService里面根据intent获取到bundle携带的信息即可。
那么问题来了,既然这么简单那就用这种方式不就好了吗?
然而在实际开发中并不止是传递一个字符这么简单。如果要传递一个对象呢?
确实,我们发现Bundle在传递参数时是可以携带可序列化的对象的。
bundle.putParcelable("ParcelableClass",books);
这种方式在同一个进程里面是可行的,然鹅在多进程中就会出错了,会出现“Class not find”这种错误。原因是定义的boos类是属于当前进程的,其他进程获取不到,即使你把该类复制到新的进程里面也不可能被反序列化出来,因为在底层上他们已经不是同一个类了。
那么bundle到底支持哪些类型的数据呢?
1.基本数据类型
2.可序列化的对象(实现了Parcellable接口,实现了 Serializable接口的对象)
3.以及一些Android支持的特殊对象
那么要在进程之间传递对象该怎么实现呢?
gson解析成json字符串然后传递
Intent intent = new Intent(this,BookManagerService.class);
Bundle bundle = new Bundle();
Books books = new Books(1,"ming");
Gson gson = new Gson();
bundle.putString("bundle",gson.toJson(books));
intent.putExtras(bundle);
bindService(intent,mConnection,BIND_AUTO_CREATE);
这里将可序列化的对象用gson转换为json字符串,实现使用bundle传递可序列化对象。在BookManagerService里面再获取到books对象
Bundle bundle = intent.getExtras();
Log.e("mzy","bundle.getString()"+bundle.getString("bundle"));
但是书中没有提到使用json传递的方式来实现进程间通信。当然还是有更炫酷的实现方式,请往下看。
2.使用文件共享
好吧,个人感觉这种方式其实并没有多大卵用,除非是一些长期需要使用的信息使用这种方式还是挺好的,作为缓存的方式。
这个就是一个进程写文件,一个进程读文件的方式实现进程间通信的。
大体就是用的Java读写文件的方式。很简单就不列出来了,但是使用的时候还是要注意一些事情的
1.并发读/写导致数据不是最新数据
2.并发写,导致数据错误
3.SharedPreferences也是一种文件读写的方式。这个用在文件共享实现进程通信是不可取的。因为系统会对SharedPreferences进行缓存,导致数据不是最新数据。
3.使用Messenger
使用Messenger传递Message,可以实现进程间通信。其底层实现是AIDL,对AIDL进行了封装,使用起来比较简单。下面看看代码实现。
分为服务端和客户端两个进程
3.1服务端接收客户端消息
3.1.1服务端进程
在服务端创建一个Service来处理客户端的请求,创建一个Handle,并通过它来创建一个Messenger对象,再在Service的onBind中返回这个Messenger对象底层的Binder即可,说的太模糊,还是看服务端的代码吧
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 :
Bundle bundle1 = msg.getData();
Log.i(TAG,"receive msg from Client :"+bundle1.getString("msg"));
break;
default:
super.handleMessage(msg);
}
}
}
private final Messenger mMessenger = new Messenger(new MessengerHandler());
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
内容不多用一个Handle创建一个Messenger,然后在onBInd里面返回Mes的BInder,handler里面处理接收到的信息
3.1.2客户端进程
客户端首先要绑定服务端的Service,然后通过服务端返回的IBinder对象创建一个Messenger,就是通过这个Messenger对象给服务端发送消息的。,发送的消息类型为Message对象。
public class MessengerActivity extends AppCompatActivity {
private static final String TAG = "MessengerActivity";
private Messenger messenger;
//绑定Service
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//获取Messenger
messenger = new Messenger(iBinder);
//创建Message
Message msg = Message.obtain(null,MyConstants.MSG_FROM_CLIENT);
Bundle data = new Bundle();
data.putString("msg","hello i am client.");
msg.setData(data);
try {
//发送消息
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
//链接失败处理
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(MessengerActivity.this,MessengerService.class);
bindService(intent,mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
//记得注销
unbindService(mConnection);
super.onDestroy();
}
}
好了,这样就实现了使用Messenger进程间通信了。不可以只是停留在客户端单相思的程度,当然要你来我往情意绵绵,那我们来实现一下互相之间的通信
3.2客户端与服务端交互
道理其实都差不多的,服务端在收到消息以后再给客户端发送一条消息即可。
3.2.1服务端修改
public void handleMessage(Message msg) {
switch (msg.what){
case MyConstants.MSG_FROM_CLIENT :
Bundle bundle1 = msg.getData();
Log.i(TAG,"receive msg from Client :"+bundle1.getString("msg"));
Messenger client = msg.replyTo;
Message replyMessage = Message.obtain(null,MyConstants.MSG_FROM_SERVICE);
Bundle bundle = new Bundle();
bundle.putString("reply","ok i got your message");
replyMessage.setData(bundle);
try {
client.send(replyMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
3.2.2客户端修改
public class MessengerActivity extends AppCompatActivity {
private static final String TAG = "MessengerActivity";
private Messenger messenger;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
messenger = new Messenger(iBinder);
Message msg = Message.obtain(null,MyConstants.MSG_FROM_CLIENT);
Bundle data = new Bundle();
data.putString("msg","hello i am client.");
msg.setData(data);
//将客户端的接收用的messenger传给服务端。
msg.replyTo = getReplyMessenger;
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
private Messenger getReplyMessenger = 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 message from service :"+msg.getData().getString("reply"));
break;
default:
super.handleMessage(msg);
}
}
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(MessengerActivity.this,MessengerService.class);
bindService(intent,mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
}
}
3.3Messenger实现多进程通信小结
Messenger使用起来还是相对简单的。可以实现一对多的多进程通信(通过绑定Service)。但是由于其传递参数依赖于Bundle,所以传递的数据类型受到了限制。而且不能很好的处理高并发情况
4.使用AIDL
要不先休息一下?下一篇再写AIDL吧。看个海贼先