【朝花夕拾】Messenger篇——Messenger使用与源码分析

前言html

      转载请声明,转自【http://www.javashuo.com/article/p-ptlynjkg-e.html】,谢谢!java

      提起跨进程通讯,大多数人首先会想到AIDL。咱们知道,用AIDL来实现跨进程通讯,须要在客户端和服务端都添加上aidl文件,并在服务端的Service中实现aidl对应的接口。若是还须要服务端给客户端发送信息,还须要再添加回调相关的aidl文件,以及使用RemoteCallbackList来辅助实现该功能。在个人另一篇文章【朝花夕拾】Android性能篇之(七)Android跨进程通讯篇中,就专门介绍过AIDL来实现客户端和服务端互相通讯的方式,不清楚的能够看看这篇文章的介绍。本文将介绍一下另一种更简单的方式——Messenger,来实现客户端和服务端跨进程互相通讯。android

       本文的主要内容以下:服务器

 

 

1、Messenger简介多线程

       Messenger翻译为信使,顾名思义,就是用于传递信息的,经过它能够在不一样进程中传递Message对象。在Message中放入咱们须要传递的信息,而后经过Messenger将Message传递给对方,就能够轻轻松松实现跨进程数据传递。实际上Messenger是一种轻量级的IPC(跨进程通讯)方式,它的底层仍然是实现的AIDL。它是一种基于消息的进程通讯,就像子线程和UI线程发送消息那样,Demo中服务端和客户端使用的Handler,正好说明了这一点。app

 

2、Messenger使用代码示例ide

       话很少说,我们这里看看一个完整的Demo,来直观感觉一下Messenger的使用。本Demo演示的功能很简单,客户端发送消息给服务端,服务端收到消息后再发送消息给客户端做为响应。源码分析

  一、服务端代码实现post

 1 public class MessengerService extends Service {
 2     private static final String TAG = "Messenger-Demo";
 3     private static final int MSG_CLIENT = 0x001;
 4     private static final int MSG_SERVER = 0X002;
 5     private static final String KEY_CLIENT = "key_client";
 6     private static final String KEY_SERVER = "key_server";
 7 
 8     private final Messenger mMessenger = new Messenger(new MessageHandler());
 9 
10     @Nullable
11     @Override
12     public IBinder onBind(Intent intent) {
13         return mMessenger.getBinder();
14     }
15 
16     private static class MessageHandler extends Handler {
17         @Override
18         public void handleMessage(Message msg) {
19             switch (msg.what) {
20                 case MSG_CLIENT:
21                     Log.d(TAG, "receive msg from Client:" + msg.getData().getString(KEY_CLIENT));
22                     Messenger messenger = msg.replyTo;
23                     Message serverMsg = Message.obtain();
24                     serverMsg.what = MSG_SERVER;
25                     Bundle bundle = new Bundle();
26                     bundle.putString(KEY_SERVER, "Hello Client! I am fine, thank you");
27                     serverMsg.setData(bundle);
28                     try {
29                         messenger.send(serverMsg);
30                     } catch (RemoteException e) {
31                         e.printStackTrace();
32                     }
33                     break;
34                 default:
35                     super.handleMessage(msg);
36             }
37         }
38     }
39 }

       对应清单文件中的注册性能

1 <service
2     android:name=".MessengerService "
3     android:exported="true"/>

这里须要注意的是第三行,该Service须要提供给其它应用调用,须要将该属性值设置为true。

  二、客户端代码实现

 1 public class MessengerClientActivity extends AppCompatActivity {
 2 
 3     private static final String TAG = "Messenger-Demo";
 4     private static final int MSG_CLIENT = 0x001;
 5     private static final int MSG_SERVER = 0X002;
 6     private static final String KEY_CLIENT = "key_client";
 7     private static final String KEY_SERVER = "key_server";
 8     private static final String SERVER_PKGNAME = "com.example.messageserver";
 9     private static final String SERVICE_PATH = "com.example.messageserver.MessengerService";
10     private Messenger mRemoteMessenger;
11     private Messenger mLocalMessenger = new Messenger(new MessengerClientHandler());
12 
13     @Override
14     protected void onCreate(Bundle savedInstanceState) {
15         super.onCreate(savedInstanceState);
16         setContentView(R.layout.activity_main);
17         Log.d(TAG,"onCreate");
18         bindService();
19     }
20 
21     private void bindService() {
22         Intent intent = new Intent();
23         ComponentName componentName = new ComponentName(SERVER_PKGNAME, SERVICE_PATH);
24         intent.setComponent(componentName);
25         bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
26     }
27 
28     private static class MessengerClientHandler extends Handler {
29         @Override
30         public void handleMessage(Message msg) {
31             switch (msg.what) {
32                 case MSG_SERVER:
33                     Log.d(TAG, "receive msg from Server:" + msg.getData().getString(KEY_SERVER));
34                     break;
35                 default:
36                     break;
37             }
38             super.handleMessage(msg);
39         }
40     }
41 
42     private ServiceConnection mServiceConnection = new ServiceConnection() {
43         @Override
44         public void onServiceConnected(ComponentName name, IBinder service) {
45             mRemoteMessenger = new Messenger(service);
46             Message clientMsg = Message.obtain();
47             clientMsg.what = MSG_CLIENT;
48             Bundle bundle = new Bundle();
49             bundle.putString(KEY_CLIENT, "Hello,Server! How are you ?");
50             clientMsg.setData(bundle);
51             clientMsg.replyTo = mLocalMessenger;
52             try {
53                 mRemoteMessenger.send(clientMsg);
54             } catch (RemoteException e) {
55                 e.printStackTrace();
56             }
57         }
58 
59         @Override
60         public void onServiceDisconnected(ComponentName name) {
61 
62         }
63     };
64 
65     @Override
66     protected void onDestroy() {
67         super.onDestroy();
68         unbindService(mServiceConnection);
69     }
70 }

  三、运行

       运行时先启动服务端,再启动客户端,能够看到以下log信息:

1 15185-15185/com.example.messageserver D/Messenger-Demo: receive msg from Client:Hello,Server! How are you ?
2 14269-14269/com.example.messageclient D/Messenger-Demo: receive msg from Server:Hello Client! I am fine, thank you

 这样客户端和服务端就完成了一次互相通讯。从代码上来看,就能感觉到,相比于直接使用AIDL方式,Messenger简洁方便了不少。

 

3、Messenger的使用步骤流程图

       经过前面的Demo直观感觉了Messenger的使用,其交互流程大体为如下六步:

 

 

       对照Demo和上图,应该可以轻松理解Messenger的交互流程了。这里须要注意的是,实际上给Server端的Handler发送消息的Messenger,是结合服务端返回的IBinder实例来生成的服务端远程代理;给客户端Handler发送消息的Messenger也是第4步中发送给服务端的客户端本地Messenger, 能够理解为是本身的Messenger给本身的Handler在发送消息。

 

4、Messenger和AIDL的联系与区别

       前面咱们说过Messager的底层仍是实现的AIDL,这是它们的联系。它们的区别是:

    (1)Messenger使用起来比AIDL简洁方便。

    (2)AIDL的客户端接口会同时向服务端发送多个请求,服务端须要应用多线程处理。而Messenger会将全部请求排入队列(Handler对应的MessageQueue),让服务器一次处理一个调用,不用处理多线程问题。大多数状况下,服务端不须要执行多线程处理此时选择Messenger方式更合适,而若是客户端的请求要求服务端执行多线程处理,就应该使用AIDL来实现,选择哪种,仍是须要根据实际状况来选择。

 

5、Messenger源码分析

       到这里,就讲完了Messenger的基本使用方法,以及基本知识,但咱们仍然须要分析源码来更深刻理解Messenger,不能仅停留在应用的层面。下面咱们大体按照按照第4点中的“客户端和服务端交互流程图”中的步骤,来分析一下源码。

 

  一、Server端Messenger的建立以及onBinder回调方法返回值流程分析

       当Client端经过bindService和Server端bind时,会回调用MessengerService中的onBind方法,并返回一个IBinder对象。

1 //============MessengerService.java===========
2 private final Messenger mMessenger = new Messenger(new MessageHandler());
3 public IBinder onBind(Intent intent) {
4     return mMessenger.getBinder();
5 }

第4行的mMessenger变量,它在第2行中建立,咱们跟进到源码中看一下它的构造方法:

 1 //=============Messenger.java============
 2 private final IMessenger mTarget;
 3 /**
 4  * Create a new Messenger pointing to the given Handler.  Any Message
 5  * objects sent through this Messenger will appear in the Handler as if
 6  * {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had
 7  * been called directly.
 8  * 
 9  * @param target The Handler that will receive sent messages.
10  */
11 public Messenger(Handler target) {
12     mTarget = target.getIMessenger();
13 }
14 
15 //==============Handler.java===========
16 final IMessenger getIMessenger() {
17     synchronized (mQueue) {
18         if (mMessenger != null) {
19             return mMessenger;
20         }
21         mMessenger = new MessengerImpl();
22         return mMessenger;
23     }
24 }
25 ......
26 private final class MessengerImpl extends IMessenger.Stub {
27     public void send(Message msg) {
28         msg.sendingUid = Binder.getCallingUid();
29         Handler.this.sendMessage(msg);
30     }
31 }

        第3~10行的注释对理解Messenger颇有用,这里简单翻译一下:建立一个新的指向给定Handler(也就是MessengerService类中的自定义的MessengerHandler)的Messenger。当Handler.sendMessage(Message)被直接调用时,任何经过该Messenger发送的Message对象都会出如今这个Handler(即MessengerHandler)中。参数是Handler 类型的targe,它将接收发送来的message。

       经过上面的源码跟踪,能够发现,这里建立的Messenger,即mMessenger变量,实际上就是MessengerImpl对象。它继承自IMessenger.Stub,看到这里,咱们就可以很容易联想到AIDL了,经过AIDL的方式,Service端回调的onBind方法,返回的自定义Binder就是就是这样写的。若是有编译过AIDL项目,跟进Stub后能够看到以下内容:

1 public static abstract class Stub extends android.os.Binder implements xxx
2 //============Binder.java============
3 public class Binder implements IBinder {...}

Stub继承自android.os.Binder,可见MessengerImpl实际上也是一个Binder对象,而Binder是IBinder的实现类。如今咱们就搞清楚了在建立Messenger对象时所建立的mTarget,实际上就是一个Binder。(这里讲到的AIDL相关的内容,能够参照文章开头处提到的文章,里面有讲到AIDL编译后生成的内容)。

       再看mMessenger调用的getBinder()方法。

 1 //=============MessengerService.java=========
 2 
 3 public IBinder onBind(Intent intent) {
 4     return mMessenger.getBinder();
 5 }
 6 
 7 //============Messenger.java=============
 8 /**
 9  * Retrieve the IBinder that this Messenger is using to communicate with
10  * its associated Handler.
11  * 
12  * @return Returns the IBinder backing this Messenger.
13  */
14 public IBinder getBinder() {
15     return mTarget.asBinder();
16 }

 第7~13行注释有说明:该方法用于获取IBinder,当前Messenger(即mMessenger)正在用这个IBinder和与本身关联的Handler进行通讯。这里仍然须要借助aidl生成的java接口文件中的内容(下面这个Stub在前面提到过)来理解:

1 public static abstract class Stub extends android.os.Binder implements xxx {
2       ......
3       @Override
4         public android.os.IBinder asBinder() {
5             return this;
6         }
7       ......
8 }

经过前面的分析,咱们已经知道了继承链:MessengerImpl extends IMessenger.Stub extends android.os.Binder implements IBinder。而mTarget是MessengerImpl的实例,咱们能够得知,mTarget.asBinder()返回的就是MessengerImpl对象(这里不太肯定这个结论是否正确,但返回的是Stub对象是显而易见的)。这里再次对比AIDL实现方式中onBind方法的返回形式,其常见写法是:return new MyBinder(),这里的MyBinder extends Stub,这样一对比,就和AIDL不谋而合了。

        到这里,就分析完了Server端建立Messenger,以及回调onBinder方法的返回值源码流程。

 

  二、Client端远程Messenger的建立

        MessengerClientActivity类的第45行,bindService成功后,会建立一个用于和Server端发送消息的远程Messenger:

//======================MessengerClientActivity.java==================
1
public void onServiceConnected(ComponentName name, IBinder service) { 2 mRemoteMessenger = new Messenger(service); 3 ...... 4 }

这里咱们又看到了另一种建立Messenger的方式,咱们看看源码:

//=====================Messenger.java=================
1
/** 2 * Create a Messenger from a raw IBinder, which had previously been 3 * retrieved with {@link #getBinder}. 4 * 5 * @param target The IBinder this Messenger should communicate with. 6 */ 7 public Messenger(IBinder target) { 8 mTarget = IMessenger.Stub.asInterface(target); 9 }

咱们仍然先翻译一下注释:从一个原始的IBinder建立一个Messenger,该IBinder以前经过getBinder方法来获取获得。参数为IBinder类型,当前Messenger应该和这个IBinder进行通讯。当咱们看到第8行的时候,是否是又仿佛看到了AIDL中客户端建立服务端代理类呢?

       结合上述代码的分析,已经很明确地验证了第二节中说的,Messenger的底层仍然是AIDL!

 

  三、Client端向Server端发送消息

        在MessengerClientActivity类的第53行,也就是下面的第7行,就是远程Messenger向服务端发送消息。

//===============MessengerClientActivity.java=============
1
@Override 2 public void onServiceConnected(ComponentName name, IBinder service) { 3 mRemoteMessenger = new Messenger(service); 4 Message clientMsg = Message.obtain(); 5 ...... 6 try { 7 mRemoteMessenger.send(clientMsg); 8 } catch (RemoteException e) { 9 e.printStackTrace(); 10 } 11 }

咱们查看send的源码:

 1 //============Messenger.java===========
 2 /**
 3  * Send a Message to this Messenger's Handler.
 4  * 
 5  * @param message The Message to send.  Usually retrieved through
 6  * {@link Message#obtain() Message.obtain()}.
 7  * 
 8  * @throws RemoteException Throws DeadObjectException if the target
 9  * Handler no longer exists.
10  */
11 public void send(Message message) throws RemoteException {
12     mTarget.send(message);
13 }
14 
15 //=============Handler.java============
16 private final class MessengerImpl extends IMessenger.Stub {
17     public void send(Message msg) {
18         msg.sendingUid = Binder.getCallingUid();
19         Handler.this.sendMessage(msg);
20     }
21 }

咱们仍然先简单看看注释:发送Message给该Messenger的Handler(该Messenger来自于Server端,因此这里的Handler也就是Server端自定义那个Handler)。第1点中讲过,mTarget就是MessengerImpl的实例,因此第12行就是执行的第17行。第19行咱们再熟悉不过了,Handler发送Message,因此咱们这里就很明确了,远程Messenger的send方法,实际上就是经过Handler来发送数据的。

 

  四、Server端向Client端发送消息

       实现Server端向Client端发送数据,关键代码以下:

 1 //=======  MessengerClientActivity========
 2 private Messenger mLocalMessenger = new Messenger(new MessengerClientHandler());
 3 @Override
 4 public void onServiceConnected(ComponentName name, IBinder service) {
 5     mRemoteMessenger = new Messenger(service);
 6     Message clientMsg = Message.obtain();
 7     ......
 8     clientMsg.replyTo = mLocalMessenger;
 9     ......
10     try {
11         mRemoteMessenger.send(clientMsg);
12     } catch (RemoteException e) {
13         e.printStackTrace();
14     }
15 }
16 
17 //==========AidlService========
18 Messenger messenger = msg.replyTo;
19 Message serverMsg = Message.obtain();
20 ......
21 try {
22     messenger.send(serverMsg);
23 } catch (RemoteException e) {
24     e.printStackTrace();
25 }

这里关键中的关键是第8行,和第18行。客户端须要将本地Messenger发送给Server端,也就是第8行,其源码以下:

1 //==========Message.java===========
2 public Messenger replyTo;

这里的replyTo是一个Messenger类型的,第8行就将本地Messenger装进Message中,发送到Server端了。在Server端就会接收该Messenger,如第18行中所示。这样,Server端就拿到了Client端的本地Messenger对象,而后就能够经过这个Messenger给Client端发送消息了,接收者为Client端本地Messenger关联的Handler,这样就实现了服务端向客户端发送消息。

       到这里,Messenger通讯流程的源码分析就结束了。简单来讲,Messenger原理就是封装了AIDL,以及使用Handler来发送消息。

 

结语

       因为笔者水平有限,文章中若是有描述不许确或者不稳当的地方,还请读者不吝赐教,很是感谢!

相关文章
相关标签/搜索