转载请注明出处: http://blog.youkuaiyun.com/a992036795/article/details/51593543
一、Messenger是android中一种轻量级的IPC方案,它的底层实现同aidl一样。
我们先来了解一下Messenger这个类,首先看一下Messenger的构造方法,它的主要有2个构造方法。
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);
}
第一个构造方法,接受一个handle对象,然后使用 mTarget = target.getIMessenger(); 通过调用 Handler的getIMessenger方法返回一个实现了IMessenger接口的binder对象。为什么这样说呢? 我们参考一下Handle中 getIMessager方法就知道了。
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
可以看到,这和aidl是一样的,他返回了一个实现IMessenger接口的Binder对象那个。如果有framework 源码的话,还可以查看IMessenger.aidl文件
我这里给出IMessenger.aidl文件的内容:
package android.os;
import android.os.Message;
/** @hide */
oneway interface IMessenger {
void send(in Message msg);
}
在来看第二个构造方法,第二个构造方法调用了 mTarget = IMessenger.Stub.asInterface(target);这里很明显看以看出跟aidl的使用一样,根据参数binder,获得了真正用来通信的那个binder对象,这个方法的返回有2中可能,一种是返回Stub,另一种返回 Proxy(夸进程时) 还记得吗?
可以参考我的上一篇博客:http://blog.youkuaiyun.com/a992036795/article/details/51579711。
好了,原理大概就是这样。写的也比较粗略,请见谅。
二、使用。
讲完了原理,我们来看看如何使用它。我们新建一个SimpleService 类
重新onBind方法。
public class SimpleService extends Service {
private static final String TAG = "SimpleService";
static final int FIRST_RECEIVER_CODE = 0;
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case FIRST_RECEIVER_CODE:
Log.i(TAG, "handleMessage: from client: " + msg.getData().getString("msg"));
break;
}
}
};
private Messenger mMessenger = new Messenger(mHandler);
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
可以看到,我们使用一个Handle 通过Messenger的第一个构造函数创建了一个Messenger用来和客户端通信,注意在onBind()方法中使用 mMessenger.getBinder()方法返回了底层用来通信的那个binder。
这里顺便给出getBinder()在Messenger类中的实现:
public IBinder getBinder() {
return mTarget.asBinder();
}
mTarget就是构造方法中赋值的那个binder.
这样我们在客户端进行bindService的时候就可以使用这个binder了。
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, "onServiceConnected: ");
mServerMessenger = new Messenger(service);
Message messager = Message.obtain();
messager.what =SimpleService.FIRST_RECEIVER_CODE ;
Bundle bundle = new Bundle();
bundle.putString("msg","你好,我来自客户端");
messager.setData(bundle);
try {
/*发送*/
mServerMessenger.send(messager);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "onServiceDisconnected: ");
}
} ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,SimpleService.class);
bindService(intent,conn,BIND_AUTO_CREATE) ;
}
这里我们使用服务端传过来的 这个Binder 又重新构造出了一个Messenger类,用来和服务端通信,他们实际使用的是同一个binder对象。他们通过互相发送Message来相互通信。为什么可以使用Message呢?因为Message实现了Parcelable接口哈哈~
*/
public final class Message implements Parcelable {
public int what;
public int arg1;
public int arg2;
public Object obj;
// 可以存放一个Messenger对象
public Messenger replyTo;
.....
}
另外,还可以看到Message中可以存放一个Messenger对象,那么我们就可以利用这个replayTo字段,使得客户端创建出来一个Messenger传递给服务端,然后服务端得到这个Messenger之后,来向客户端发消息。这就实现了双向通信。客户端创建Messenger的方法跟服务端创建Messenger一样,也使用一个Handler来完成,所以最终代码如下:
客户端:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
static final int FIRST_RECEIVER_SERVER_CODE =1;
/*Messenger 服务端*/
private Messenger mServerMessenger ;
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case FIRST_RECEIVER_SERVER_CODE:
Log.i(TAG, "handleMessage: from server: "+msg.getData().getString("msg"));
break;
}
}
} ;
private Messenger mMessenger = new Messenger(mHandler);
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, "onServiceConnected: ");
mServerMessenger = new Messenger(service);
Message messager = Message.obtain();
messager.what =SimpleService.FIRST_RECEIVER_CODE ;
Bundle bundle = new Bundle();
bundle.putString("msg","你好,我来自客户端");
messager.setData(bundle);
/*将自己的Messenger传递给服务端*/
messager.replyTo = mMessenger;
try {
/*发送*/
mServerMessenger.send(messager);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "onServiceDisconnected: ");
}
} ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,SimpleService.class);
bindService(intent,conn,BIND_AUTO_CREATE) ;
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
}
服务端:
public class SimpleService extends Service {
private static final String TAG = "SimpleService";
static final int FIRST_RECEIVER_CODE = 0;
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case FIRST_RECEIVER_CODE:
Log.i(TAG, "handleMessage: from client: " + msg.getData().getString("msg"));
clientMessenger = msg.replyTo;
Message messager = Message.obtain();
messager.what = MainActivity.FIRST_RECEIVER_SERVER_CODE;
Bundle bundle = new Bundle();
bundle.putString("msg","你好,我已经收到了你的Messenger.");
messager.setData(bundle);
try {
/*使用客户端传来的Messenger回复客户端*/
clientMessenger.send(messager);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
};
private Messenger mMessenger = new Messenger(mHandler);
private Messenger clientMessenger;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
最终 服务端先打印:
/com.blueberry.process1 I/SimpleService: handleMessage: from client: 你好,我来自客户端
然后客户端打印:
/com.blueberry.test05 I/MainActivity: handleMessage: from server: 你好,我已经收到了你的Messenger.
可以的看到这打印分别处于不同的进程,因为我使用了多进程。使得SimpleService发生在了另一个进程。
最后啰嗦一句:使得Service发生在别的进程的方法:在Manifest文件注册Service时添加一个生命 android:process=”com.blueberry.process1” 就可以使得它运行于一个名为com.blueberry.process1的进程中了。(默认进程名为包名)
也可是使用 android:process=”: remote”使用冒号,然后后面随便写个名字,那么这个进程名称将是” 包名:remote” 他将是名称为包名的那个进程的私有进程。
本次程序使用的方式为:
<service android:name=".SimpleService"
android:enabled="true"
android:exported="true"
android:process="com.blueberry.process1"
></service>