IPC方式
————————————————————————————————————
使用文件共享,共享文件是一中不错的进程间通信方式,两个进程通过读/写同一个文件来交换数据,比如A进程把数据写入文件,B进程通过读取这个文件来获取数据。但是要注意的是,Android是基于Linux的,使得其并发读/写文件可以没有限制的执行,甚至两个线程同时对同一个文件进行写操作都是允许的。尽管可能出现这个问题。通过文件交换数据还是很好使用,除了可以交换一些文本信息外,我们还可以序列化一个对象到文件系统中,同时从另一个进程中恢复这个对象。
通过文件共享数据对文件格式是没有具体要求的,可以是文本文件,也可以是xml文件,但是SharedPreferences是一个特例,系统对于SharedPreferences的读写是有一定的缓存策略的,即在内存中会有一个SharedPreferences文件的缓存,因此在多线程模式下,系统对它的读写就变得不可靠,所以不建议在进程间通信中使用SharedPreferences。
使用Messenger,Messenger可以翻译为信使,通过它可以在不同的进程中传递Message对象,Message中放入我们需要传递的数据,就可以轻松地实现数据的进程间传递了。Messenger是一种轻量级的IPC方案,它的底层实现是AIDL。
那么如何使用Messenger呢?这分几个步骤:
- 服务端进程
首先我们需要在服务端创建一个Service来处理客户端的连接请求,同时创建一个Handler并通过它创建一个Messenger对象,然后再Service的onBind中返回这个Messenger对象底层的Binder即可。
/*
*服务端代码
**/
public class MessengerService extends Service {
private static final String TAG = MessengerService.class.getCanonicalName();
public MessengerService() {
}
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 0:{
Log.i(TAG, "recive msg from Client:" + msg.getData().getString("msg"));
//从客户端接收的消息中获得Messenger对象,用于服务端回应客户端
Messenger client = msg.replyTo;
Message replyMessage = Message.obtain(null, 1);
Bundle bundle = new Bundle();
bundle.putString("reply", "恩,你的消息我已经收到,稍后回复你。");
replyMessage.setData(bundle);
try {
client.send(replyMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
default:
super.handleMessage(msg);
}
}
}
private final Messenger mMessenger = new Messenger(new MessengerHandler());
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
// throw new UnsupportedOperationException("Not yet implemented");
//此处返回的是服务端Messenger的Binder
return mMessenger.getBinder();
}
}
- 客户端进程
客户端进程中,首先要绑定服务端的Service,绑定成功后用服务端返回的IBinder对象创建一个Messenger,系通过这个Messenger就可以向服务端发送消息了,发消息类型为Message对象。如果需要服务端能够回应客户端就和服务端一样我们还需要创建一个Handler并创建一个新的Messenger,并把这个Messenger对象通过Message的replyTo参数就可以回应客户端。
/*
*客户端代码
**/
public class MessengerActivity extends AppCompatActivity {
private static final String TAG = MessengerActivity.class.getCanonicalName();
private Messenger mMeessemger;
//创建一个接受服务端响应的Messenger对象
private Messenger mGetReplyMenssenger = new Messenger(new MessengerHandler());
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:{
Log.i(TAG, "receive msg from Service:" + msg.getData().getString("reply"));
break;
}
default:
super.handleMessage(msg);
}
}
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMeessemger = new Messenger(service);
Message message = Message.obtain(null, 0);
Bundle data = new Bundle();
data.putString("msg","hello this is client.");
message.setData(data);
//如果想得到服务端的响应,就要把接受响应的Messenger通过Message传递给服务端
message.replyTo = mGetReplyMenssenger;
try {
mMeessemger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger);
Intent intent = new Intent(this, MessengerService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnection);
}
}
通过上面的代码我们可以知道,其实服务器端和客户端就是互相得到对方Messenger的Binder对象,并利用Binder进行进程间的通信,这和AIDL的原理是一样的,所以可以理解为Messenger就是对AIDL的封装。