一,写在前面
在Android中实现IPC机制的方式有多种,例如:AIDL,ContentProvider,Messenger等。AIDL特点是提供AIDL接口的方法,ContentProvider特点是暴露数据库,Messenger特点是进程间“数据”通信,数据指对象。Messenger实现进程间数据通信是建立在绑定服务基础上,需要创建一个服务,称之为服务端;需要一个客户端,去绑定服务端。
二,了解Messenger构造方法
先来了解Messenger的两个构造方法:
/**
* Create a new Messenger pointing to the given Handler. Any Message
* objects sent through this Messenger will appear in the Handler as if
* {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had
* been called directly.
*
* @param target The Handler that will receive sent messages.
*/
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
//...
/**
* Create a Messenger from a raw IBinder, which had previously been
* retrieved with {@link #getBinder}.
*
* @param target The IBinder this Messenger should communicate with.
*/
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
Handler.this.sendMessage(msg);
}
}
IMessenger.Stub这个不就是在AIDL中服务端返回的Binder对象么;参数为IBinder的构造方法,mTarget不就是AIDL中客户端中返回的代理对象么。因此Messenger内部是对AIDL进行了封装,我们不需要使用AIDL接口,直接调用系统提供给我们的方法就可以了。上面简单分析了下Messenger内部就是封装了AIDL技术,下面将介绍如何使用Messenger。
三,服务端实现
首先是服务端,
1,创建一个Service的子类,并重写了onBinder(intent)方法;
2,创建一个Handler子类实例,并重写handleMessage(msg)方法;
3,创建一个关联handler的Messenger对象:Messenger mMessenger = new Messenger(mHandler);mHandler为第二步中的handler;
4,在onBinder(intent)方法中,调用mMessenger.getBinder()返回binder对象给客户端;
服务端的代码:
public class MyService extends Service {
private static final int MSG_FROM_CLIENT = 0;
private static final int MSG_FROM_SERVICE = 1;
private Handler mHandler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_FROM_CLIENT:
//计算值之和
int sum = msg.arg1 + msg.arg2;
//获取消息中信使
Messenger cs_messenger = msg.replyTo;
//创建新的消息对象
Message m = Message.obtain();
m.what = MSG_FROM_SERVICE;
Bundle b = new Bundle();
b.putInt("sum", sum);
m.obj = b;
//发送消息给client
try {
cs_messenger.send(m);
} catch (Exception e) {
e.printStackTrace();
}
break;
default:
break;
}
};
};
private Messenger mMessenger = new Messenger(mHandler);
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
四,客户端实现
然后是客户端:
1,调用bindService方法绑定服务端的Service,在客户端与Service成功建立连接后,
onServiceConnected方法被回调,可以获取到Binder对象;
2,创建一个客户端与服务端通信的信使,Messenger对象,Messenger cs_messenger = new
Messenger(mHandler);mHandler同服务端一样创建;
3,在onServiceConnected方法中创建Messenger对象,执行:Messenger messenger = new
Messenger(binder);
4,在onServiceConnected方法中创建Message对象,设置Message对象中必要字段what,可选字段
obj,arg1,arg2;以及replyTo(第2步中信使cs_messenger );
5,在onServiceConnected方法中调用:messenger.send(msg)发送消息;
客户端代码:
public class MainActivity extends Activity {
private MyServiceConnection conn;
private static final int MSG_FROM_CLIENT = 0;
private static final int MSG_FROM_SERVICE = 1;
private Handler mHandler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_FROM_SERVICE:
//处理service发送的消息
Bundle b = (Bundle) msg.obj;
int sum = b.getInt("sum");
Log.e("MainActivity", "sum:" + sum);
break;
default:
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setAction("com.example.messengerdemo.wang");
conn = new MyServiceConnection();
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
private Messenger cs_messenger = new Messenger(mHandler);
private class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
Log.e("MainActivity", "true");
//创建binder关联的信使对象
Messenger messenger = new Messenger(service);
//创建一个消息对象
Message msg = Message.obtain(null, MSG_FROM_CLIENT, 10, 20);
msg.replyTo = cs_messenger;//replyTo为handler关联的信使
messenger.send(msg);//信使发送消息
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
@Override
protected void onDestroy() {
if (conn != null) {
unbindService(conn);
}
super.onDestroy();
}
}
第1,3步与使用AIDL使用相同,在第3步中创建了构造函数参数为binder的Messenger对象,实际上就是执行:mTarget = IMessenger.Stub.asInterface(target)。第5步调用了Messenger的send方法发送消息,查看Messenger$send源码:
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
因此,我们可以得出这样一个结论:创建一个关联Binder的Messenger对象,并调用send(msg)方法,其实就是封装 了AIDL技术,Handler+Message。在客户端发送消息后,消息是由服务端的handleMessage(msg)处理,这里完成了一个数据由客户端-->到服务端的过程。
那么,服务端获取了消息中数据,想要给客户端传递数据,那应该怎么做呢?在服务端中handleMessage()中发送消息给客户端实现,分这样几步:
1,取出Message中的存储数据的字段obj/arg1/arg2,以及信使replyTo;
2,创建一个新的Message对象,设置字段what,obj/arg1/arg2;
3,使用第1步中的replyTo中存储信使,调用cs_messenger.send(m),将第2步中消息对象发送给客户端;
值得一提的是:第三步中发送消息的信使只能是replyTo字段存储的对象,不能是服务端创建的关联了handler对象的Messenger。
五,另外
本篇文章提供的服务端的代码中,在服务端给客户端传递数据时,消息中存储的数据放在字段obj里,大家应该注意到Integer数据先经过Bundle对象的封装,然后才赋值给msg.obj。由于是进程间传递数据,对象只能是Parcelable对象,并且赋值给字段obj的对象只能是系统的Parcelable对象,我们自定义的Parcelable对象无法通过obj传递。除了字段obj传递对象,还可以调用Message$setData(bundle)存放对象。另外,Message,Messenger都实现了Parcelable接口,因此可以进行跨进程的传输。
前面服务端向客户端通过发送消息传递了数据,客户端处理消息是在handleMessage(msg)中,见代码吧,没什么可分析的了,这样就完成了一个数据由服务端-->到客户端的过程。上面介绍了如何使用Messenger实现数据跨进程传输,客户端-->服务端,然后服务端->客户端。
这篇文章就分享到这里啦,有疑问可以留言,亦可纠错,亦可补充,互相学习...^_^