AsyncChannel使用和原理
来源:互联网 发布:提取背景音乐的软件 编辑:程序博客网 时间:2024/04/25 21:31
转载自:http://blog.csdn.net/u010961631/article/details/48179305
这篇博客的不足之处在于示例程序中的通信双方实际上是在同一个进程中运行的,虽然AsyncChannel也可以用于同一个进程内部两个handler之间的通信,不过这样有点小题大做了(因为handler自己就可以胜任这样的工作),不过从操作上流程上来讲,二者差不多,区别仅仅在于获取对端Messenger的方式不用,在参考过程中要注意这一点。
一、AsyncChannel概述
AsyncChannel在Wifi的处理机制中被大量使用,但是可惜的是该工具是一个internal的方法,没有开放给第三方应用使用,但是该工具提供的思路很有用,可以被扩展到任意两个Handle间传输数据的通道。
那么AsyncChannel究竟是什么工具呢?他的内部机制又是怎么样呢?我们先来看一下AsyncChannel的官方描述:
- * <p>An asynchronous channel between two handlers.</p>
- * <p>The handlers maybe in the same process or in another process. There
- * are two protocol styles that can be used with an AysncChannel. The
- * first is a simple request/reply protocol where the server does
- * not need to know which client is issuing the request.</p>
- * <p>In a simple request/reply protocol the client/source sends requests to the
- * server/destination. And the server uses the replyToMessage methods.
- * In this usage model there is no need for the destination to
- * use the connect methods. The typical sequence of operations is:</p>
- * <p>A second usage model is where the server/destination needs to know
- * which client it's connected too. For example the server needs to
- * send unsolicited messages back to the client. Or the server keeps
- * different state for each client. In this model the server will also
- * use the connect methods. The typical sequence of operation is:</p>
1.1、作用
AsyncChannel在两个Handler间搭建了通道,可以用于消息传输。
1.2、特点
从上面第一段英文描述可以知道AsyncChannel的两个特点:
1、AsyncChannel可以作为Handler之间的通道。2、这两个Handler可以处于同一个进程,也可以不再同一个进程。
1.3、两种工作模式
第二段和第三段英文分别描述了AsyncChannel的两种工作模式:
1、单项通道模式,在该模式下,客户端只能向服务端发起请求,服务端给出回应。2、双向通道模式,在该模式下,客户端和服务端同时连接上AsyncChannel,客户端可以向服务端发送请求,服务端也可以向客户端发送请求。
下面我们分别来介绍这两种模式的使用方法。
二、AsyncChannel通道使用方法
为了进行测试,我搭建了一个Demo程序用于测试相关功能,源码可以这里下载。由于AsyncChannel是internal的工具,因此该Demo必须要在ROM源码环境下编译并具备系统签名。
在这个Demo中,只有三个文件:MainActivity、AsyncChannelClient、AsyncChannelService、AsyncChannelServiceFull四个文件,其作用分别是:MainActivity
----负责界面搭建,里面包含:“初始化客户端和服务端并依次建立单向通道和双向通道”、“初始化客户端和服务端并直接建立双向通道”、“发送异步信息”、“发送同步信息”等四个按钮。
AsyncChannelClient
----作为客户端,向服务端发送请求。
AsyncChannelService
----作为服务端,接受客户端请求。
AsyncChannelServiceFull
----作为服务端,用于接受快速双向通道的请求。
下面来看AsyncChannel的具体使用。
2.1、单向通道建立方法
在这个Demo中,当点击“初始化客户端和服务端并依次建立单向通道和双向通道”后,就会先后启动服务端和客户端,当客户端的Server启动(onStartCommand)时,就会与服务端建立单项通道。
我们先来看点击动作的处理:- @MainActivity.java
- public void onClick(View view) {
- switch (view.getId()) {
- case R.id.start_service_btn: {
- // 启动客户端和服务端
- Intent intent = new Intent();
- intent.setComponent(new ComponentName(this, AsyncChannelService.class));
- startService(intent);
- Intent inte = new Intent();
- inte.setComponent(new ComponentName(this, AsyncChannelClient.class));
- //Action是"Normal"
- inte.setAction("Normal");
- startService(inte);
- break;
- }
- }
- }
- @AsyncChannelClient.java
- public static AsyncChannel sClientAsyncChannel;
- public int onStartCommand(Intent intent, int flags, int startId) {
- //创建本地的Handler对象
- HandlerThread handlerThread = new HandlerThread("ClientThread");
- handlerThread.start();
- Handler clientHandler = new ClientHandler(handlerThread.getLooper());
- //创建客户端的AsyncChannel
- sClientAsyncChannel = new AsyncChannel();
- String act = intent.getAction();
- //我们发送的Action就是"Normal"
- if ("Normal".equals(act)) {
- // 建立单向通道,获取服务端的Messenger对象
- Messenger serviceMessenger = AsyncChannelService.getServiceMessenger();
- //发起连接请求
- sClientAsyncChannel.connect(this, clientHandler, serviceMessenger);
- } else if ("Fast".equals(act)) {
- }
- return super.onStartCommand(intent, flags, startId);
- }
- @AsyncChannelService.java
- public static Messenger getServiceMessenger() {
- //服务端需要用自己的Handler构建Messenger然后发送给客户端
- return new Messenger(mServiceHandler);
- }
1、获取服务端的Messenger对象,该对象其实就是利用服务端的Handler构建的Messenger;
2、创建客户端自己的Handler对象;
3、创建AsyncChannel对象;
4、通过AsyncChannel对象,连接当前的Handler和服务端的Messenger,从而申请连接。
当客户端发送完connect()请求之后,客户端需要做的就是在Handler对象中等待Message消息:
- @AsyncChannelClient.java
- public void handleMessage(Message message) {
- switch (message.what) {
- case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
- if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- Log.d(tag, "Service half connected");
- }
- break;
- }
- }
- }
以上就是单项通道的建立过程,整个过程不需要服务端做任何操作。
2.2、双向通道建立方法
那么如果客户端想要创建双向通道,该如何操作呢?
首先,服务端本身需要初始化Handler,并且如果服务端准备提供双向通道,那么就需要创建自己的AsyncChannel对象。这些工作需要在客户端初始化时完成:- @AsyncChannelService.java
- public int onStartCommand(Intent intent, int flags, int startId) {
- //初始化Handler
- HandlerThread handlerThread = new HandlerThread("ServiceThread");
- handlerThread.start();
- mServiceHandler = new ServiceHandler(handlerThread.getLooper());
- //创建AsyncChannel对象
- sServiceAsyncChannel = new AsyncChannel();
- return super.onStartCommand(intent, flags, startId);
- }
也就是在刚才接收到的消息基础上,发送CMD_CHANNEL_FULL_CONNECTION请求即可:
- @AsyncChannelClient.java
- public void handleMessage(Message message) {
- switch (message.what) {
- case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
- if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- //客户端单项通道建立完成,继续申请双向通道
- sClientAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
- }
- break;
- }
- }
- @AsyncChannelService.java
- public void handleMessage(Message msg) {
- switch ((msg.what)) {
- case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
- //服务端接收到双向通道的建立请求
- //如果同意客户端建立,则需要服务端向AsyncChannel申请连接请求
- sServiceAsyncChannel.connect(AsyncChannelService.this, mServiceHandler, msg.replyTo);
- break;
- }
- }
- }
至此,双向通道建立完成,此时不仅客户端可以通过自己的AsyncChannel对象向服务端发送请求,服务端也可以通过自己的AsyncChannel对象向客户端发送请求。
以上就是双向通道的建立过程。
2.3、更有效的双向通道建立方法
上一节中介绍了双向通道的建立方法,其实这是一种“笨方法”,为什么这么说呢?我们来看一下要创建双向通道需要经过哪些步骤:
1、客户端发起connect()请求,申请建立单向通道;2、客户端接收到CMD_CHANNEL_HALF_CONNECTED,然后继续向AsyncChannel申请双向通道;
3、服务端接收到CMD_CHANNEL_FULL_CONNECTION申请,向AsyncChannel发送连接请求;
这就需要三个步骤才可以完成双向通道建立,并且最重要的是,客户端始终不知道服务端是否真正连接上了AsyncChannel(如果客户端想知道结果,还需要服务端再次发送一次确认消息)。
那么有没有一种方法,在客户端创建通道时就指定要创建双向通道呢?
这就用上fullyConnectSync()方法。通过该方法,客户端只需要一次就可以申请到双向通道,并且可以知道通道是否建立成功。
下面来看代码实现,当点击界面上“初始化客户端与服务端并快速建立双向通道”按钮后,将会触发客户端双向通道的申请:
- @MainActivity.java
- public void onClick(View view) {
- switch (view.getId()) {
- case R.id.start_service_fast_connect_btn: {
- Intent intent = new Intent();
- intent.setComponent(new ComponentName(this, AsyncChannelServiceFull.class));
- startService(intent);
- Intent inte = new Intent();
- inte.setComponent(new ComponentName(this, AsyncChannelClient.class));
- inte.setAction("Fast");
- startService(inte);
- break;
- }
- }
- }
我们先来看AsyncChannelServiceFull服务的初始化流程:
- @AsyncChannelServiceFull.java
- public int onStartCommand(Intent intent, int flags, int startId) {
- //初始化Handler对象
- HandlerThread handlerThread = new HandlerThread("ServiceThread");
- handlerThread.start();
- mServiceHandler = new ServiceHandler(handlerThread.getLooper());
- //创建AsyncChannel对象
- sServiceAsyncChannel = new AsyncChannel();
- return super.onStartCommand(intent, flags, startId);
- }
- @AsyncChannelClient.java
- public int onStartCommand(Intent intent, int flags, int startId) {
- //初始化Handler对象
- HandlerThread handlerThread = new HandlerThread("ClientThread");
- handlerThread.start();
- Handler clientHandler = new ClientHandler(handlerThread.getLooper());
- //创建AsyncChannel对象
- sClientAsyncChannel = new AsyncChannel();
- String act = intent.getAction();
- if ("Normal".equals(act)) {
- } else if ("Fast".equals(act)) {//此时的Action是"Fast"
- // 要求直接双向通道
- Handler serviceHandler = AsyncChannelServiceFull.getServiceHandler();
- int result = sClientAsyncChannel.fullyConnectSync(this, clientHandler, serviceHandler);
- if (AsyncChannel.STATUS_SUCCESSFUL == result) {
- Log.d(tag, "client full connected");
- }
- }
- return super.onStartCommand(intent, flags, startId);
- }
1、客户端不再使用connect()方法连接AsyncChannel,而是使用fullyConnectSync()方法建立双向通道;
2、调用fullyConnectSync()建立通道时,使用的是服务端的Handler对象(serviceHandler)而不是Messenger对象;
3、调用fullyConnectSync()建立通道时,此方法有个返回值,可以明确知道通道是否建立成功;
接下来我们看此时的服务端的流程。
当客户端通过fullyConnectSync()申请双向通道时,服务端就可以收到CMD_CHANNEL_FULL_CONNECTION的消息,然后服务端需要连接上AsyncChannel后回复成功的命令即可完成通道的建立:
- @AsyncChannelServiceFull.java
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
- //收到双向通道建立请求,如果服务端同意,则需要连接上AsyncChannel,然后恢复STATUS_SUCCESSFUL即可
- sServiceAsyncChannel.connect(AsyncChannelServiceFull.this, mServiceHandler, msg.replyTo);
- //将建立结果传递给客户端
- sServiceAsyncChannel.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, AsyncChannel.STATUS_SUCCESSFUL);
- break;
- }
- }
- }
从这个过程中我们看到该方式更加方便和有效,他省掉了客户端CMD_CHANNEL_HALF_CONNECTED的请求过程,而且客户端可以知道通道的建立结果。这也是官方推荐的做法。
以上就是快速双向通道的建立过程。
三、消息的使用
我们建立通道的最终目的是为了在两个Handler间传输信息,而消息又分为两类:异步消息和同步消息,接下来分别介绍这两种消息的使用方法。
3.1、异步消息使用方法
所谓异步消息,就是客户端(或服务端)发送消息之后在Handler中等待回应,而不是立刻拿到消息结果。无论是客户端或者是双向通道中的服务端,都可以通过自己的AsyncChannel对象向对方发送异步消息。
在该Demo中,当点击界面上的“发送异步信息”按钮时,就会在客户端中向服务端发送一个MainActivity.MSG_ASYNC_REQ的请求,接下来在Server端的handleMessage中就能收到该请求,我们在Server收到该请求后,创建一个MSG_SYNC_REPLY的消息,并在其中放入一个字串“ServiceAsyncReply”返回给客户端,接下来客户端就可以在自己的handleMessage中检测到该回应,最终我们在客户端的handleMessage中把该字串打印出来。接下来看具体的代码:
当点击“客户端发送异步消息”的按钮时,进入客户端的sendMsgToService()方法中:
- @AsyncChannelClient.java
- public static void sendMsgToService() {
- // 客户端用AsyncChannel给服务端发送MSG_ASYNC_REQ的请求
- sClientAsyncChannel.sendMessage(MainActivity.MSG_ASYNC_REQ);
- }
- @AsyncChannelService.java
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MainActivity.MSG_ASYNC_REQ: {
- //接收到客户端请求
- Message reply = msg.obtain();
- reply.what = MainActivity.MSG_ASYNC_REPLY;
- reply.obj = "ServiceAsyncReply";
- try {
- //给客户端发送回应,回应的内容中what=MSG_ASYNC_REPLY,obj="ServiceAsyncReply"
- msg.replyTo.send(reply);
- } catch (RemoteException e) {
- }
- break;
- }
- }
- @AsyncChannelClient.java
- public void handleMessage(Message message) {
- switch (message.what) {
- case MainActivity.MSG_ASYNC_REPLY: {
- //收到服务端回应,并将服务端放入的字串打印出来,异步消息结束
- String msg = (String) message.obj;
- Log.d(tag, "get service async reply msg = " + msg);
- break;
- }
- }
- }
至此就完成了整个异步消息的调用。
3.2、同步消息使用方法
从上面的异步消息看到,无论是客户端发送消息还是服务端返回消息,都是异步的,都需要在发送完毕后被动等待消息结果,而同步消息就是客户端(或服务端)发送消息之后可以直接拿到返回值。
接下来我们通过Demo来演示同步消息的使用方法。在该Demo中,当点击“发送同步信息”按钮后,客户端将会给服务端发送一个“MSG_SYNC_REQ”的同步消息,然后等待返回值,此时的Server端将会收到该消息,等服务端处理完毕后通过replyToMessage()返回后,客户端就收到了返回值,整个过程对于客户端来说,是同步的,也就是说调用后立刻拿到了消息回应。
我们先来看客户端发送同步信息的方式:
- @AsyncChannelClient.java
- public static void sendSyncMsgToService() {
- Message replyMsg = sClientAsyncChannel.sendMessageSynchronously(MainActivity.MSG_SYNC_REQ);
- String msg = (String) replyMsg.obj;
- Log.d(tag, "get service sync reply msg = " + msg);
- }
- @AsyncChannelService.java
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MainActivity.MSG_SYNC_REQ: {
- //服务端接收到同步消息请求
- Message reply = msg.obtain();
- reply.what = MainActivity.MSG_SYNC_REPLY;
- reply.obj = "ServiceSyncReply";
- //将返回值发送给客户端
- sServiceAsyncChannel.replyToMessage(msg, reply);
- break;
- }
- }
- }
这就是同步消息的使用方法。
四、AsyncChannel通道的内部机制
以上通过Demo介绍了AsyncChannel的使用方法,接下来我们介绍AsyncChannel的内部原理。
4.1、单向通道的建立过程
从前面介绍的通道使用方法来看,第一种双向通道是在单向通道基础上搭建的,我们先来看单项通道的建立过程。
从通道的建立方法可以知道,创建通道需要三个步骤:1、准备服务端的Messenger对象;
2、创建本地的Handler对象;
3、创建AsyncChannel对象,然后调用connect()方法。
其中前两个条件容易满足,下面我们主要分析AsyncChannel的创建过程和connect()方法。
我们先来看一下AsyncChannel的属性:
- public class AsyncChannel {}
- @AsyncChannel.java
- public AsyncChannel() {
- }
- public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
- connected(srcContext, srcHandler, dstMessenger);
- replyHalfConnected(STATUS_SUCCESSFUL);
- }
- public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
- //初始化一些变量
- mSrcContext = srcContext;
- mSrcHandler = srcHandler;
- mSrcMessenger = new Messenger(mSrcHandler);
- mDstMessenger = dstMessenger;
- }
然后我们接着看connect()中的第二个方法:
- private void replyHalfConnected(int status) {
- //准备CMD_CHANNEL_HALF_CONNECTED消息
- Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED);
- msg.arg1 = status;
- msg.obj = this;
- msg.replyTo = mDstMessenger;
- if (mConnection == null) {
- mDeathMonitor = new DeathMonitor();
- try {
- //监听远端的服务是否死掉
- mDstMessenger.getBinder().linkToDeath(mDeathMonitor, 0);
- } catch (RemoteException e) {
- mDeathMonitor = null;
- msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
- }
- }
- //将CMD_CHANNEL_HALF_CONNECTED发送给本地,也就是客户端
- mSrcHandler.sendMessage(msg);
- }
然后AsyncChannel的connect()就调用结束,他的调用过程可以分为两步:
1、初始化AsyncChannel中的本地和远程的Messenger对象;
2、向本地(也就是客户端)发送CMD_CHANNEL_HALF_CONNECTED的消息;
至此,单项通道建立完毕。
该流程可以用如下图来描述:
4.2、双向通道的建立过程
下面介绍双向通道的建立过程。前面的使用方法中我们知道,双向通道的建立需要在客户端收到CMD_CHANNEL_HALF_CONNECTED消息后向AsyncChannel对象发送CMD_CHANNEL_FULL_CONNECTION消息完成的,也就是如下的入口:
- public void handleMessage(Message message) {
- switch (message.what) {
- case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
- //向AsyncChannel申请双向通道
- sClientAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
- break;
- }
- }
- }
- @AsyncChannel.java
- public void sendMessage(int what) {
- Message msg = Message.obtain();
- msg.what = what;
- sendMessage(msg);
- }
- public void sendMessage(Message msg) {
- msg.replyTo = mSrcMessenger;
- try {
- //向mDstMessenger发送消息
- mDstMessenger.send(msg);
- } catch (RemoteException e) {
- replyDisconnected(STATUS_SEND_UNSUCCESSFUL);
- }
- }
从前面的使用方法中介绍过,当服务端收到该消息后,将会通过connect()方法将自己连接上AsyncChannel:
- @AsyncChannelService.java
- public void handleMessage(Message msg) {
- switch ((msg.what)) {
- case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
- //服务端接收到双向通道的建立请求
- //如果同意客户端建立,则需要服务端向AsyncChannel申请连接请求
- sServiceAsyncChannel.connect(AsyncChannelService.this, mServiceHandler, msg.replyTo);
- break;
- }
- }
- }
- @AsyncChannel.java
- public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
- //做同样的初始化动作
- connected(srcContext, srcHandler, dstMessenger);
- //然后告诉服务端CMD_CHANNEL_HALF_CONNECTED
- replyHalfConnected(STATUS_SUCCESSFUL);
- }
从这个过程来看,其实双向通道的建立过程就是在客户端和服务端分别连接(connect)上自己的AsyncChannel对象的过程。
下面就是双向通道的建立流程图:
4.3、更有效的双向通道的建立过程
下面我们来看快速双向通道的建立过程。
该过程是通过客户端使用fullyConnectSync()方法来触发的:- @AsyncChannel.java
- public int fullyConnectSync(Context srcContext, Handler srcHandler, Handler dstHandler) {
- int status = connectSync(srcContext, srcHandler, dstHandler);
- if (status == STATUS_SUCCESSFUL) {
- Message response = sendMessageSynchronously(CMD_CHANNEL_FULL_CONNECTION);
- status = response.arg1;
- }
- return status;
- }
- public int connectSync(Context srcContext, Handler srcHandler, Handler dstHandler) {
- return connectSync(srcContext, srcHandler, new Messenger(dstHandler));
- }
- public int connectSync(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
- connected(srcContext, srcHandler, dstMessenger);
- return STATUS_SUCCESSFUL;
- }
- public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
- //初始化变量
- mSrcContext = srcContext;
- mSrcHandler = srcHandler;
- mSrcMessenger = new Messenger(mSrcHandler);
- mDstMessenger = dstMessenger;
- }
然后来看sendMessageSynchronously()方法,记得此时传递的消息是CMD_CHANNEL_FULL_CONNECTION:
- public Message sendMessageSynchronously(int what) {
- Message msg = Message.obtain();
- msg.what = what;
- Message resultMsg = sendMessageSynchronously(msg);
- return resultMsg;
- }
- public Message sendMessageSynchronously(Message msg) {
- Message resultMsg = SyncMessenger.sendMessageSynchronously(mDstMessenger, msg);
- return resultMsg;
- }
- private static Message sendMessageSynchronously(Messenger dstMessenger, Message msg) {
- //创建SyncMessenger对象
- SyncMessenger sm = SyncMessenger.obtain();
- try {
- if (dstMessenger != null && msg != null) {
- //将SyncMessenger的Messenger放入消息包中
- msg.replyTo = sm.mMessenger;
- synchronized (sm.mHandler.mLockObject) {
- //将CMD_CHANNEL_FULL_CONNECTION发送给远端的服务
- dstMessenger.send(msg);
- //阻塞监听唤醒
- sm.mHandler.mLockObject.wait();
- }
- } else {
- sm.mHandler.mResultMsg = null;
- }
- } catch (InterruptedException e) {
- sm.mHandler.mResultMsg = null;
- } catch (RemoteException e) {
- sm.mHandler.mResultMsg = null;
- }
- Message resultMsg = sm.mHandler.mResultMsg;
- sm.recycle();
- //将结果返回给客户端
- return resultMsg;
- }
那么SyncMessenger是如何同步传输消息的呢?
其原理就是当向远端的服务发送消息之后,SyncMessenger就进入阻塞状态(也就是停留在wait这里),等待远程服务端的回应,当拿到返回消息之后,将会唤醒SyncMessenger,然后再将结果返回给客户端。
结合代码来看就是,在将消息发送给服务端之前,将当前SyncMessenger的Messenger对象作为replyTo存放在消息包中:
- msg.replyTo = sm.mMessenger;
- dstMessenger.send(msg);
- sm.mHandler.mLockObject.wait();
在前面我们介绍过,当服务端接收到该请求后,如果同意建立双向通道,则需要connect()之后给出OK的回应,也就是:
- @AsyncChannelServiceFull.java
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
- //先连接上AsyncChannel
- sServiceAsyncChannel.connect(AsyncChannelServiceFull.this, mServiceHandler, msg.replyTo);
- //然后给出OK的回应
- sServiceAsyncChannel.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, AsyncChannel.STATUS_SUCCESSFUL);
- break;
- }
- }
- }
- @AsyncChannel.java
- public void replyToMessage(Message srcMsg, int what, int arg1) {
- Message msg = Message.obtain();
- msg.what = what;
- msg.arg1 = arg1;
- replyToMessage(srcMsg, msg);
- }
- public void replyToMessage(Message srcMsg, Message dstMsg) {
- try {
- dstMsg.replyTo = mSrcMessenger;
- //这里的replyTo记录的就是当初的SyncMessenger的Handler对象
- srcMsg.replyTo.send(dstMsg);
- } catch (RemoteException e) {
- log("TODO: handle replyToMessage RemoteException" + e);
- e.printStackTrace();
- }
- }
- @AsyncChannel.java
- private class SyncHandler extends Handler {
- public void handleMessage(Message msg) {
- mResultMsg = Message.obtain();
- mResultMsg.copyFrom(msg);
- synchronized(mLockObject) {
- //唤醒SyncMessenger
- mLockObject.notify();
- }
- }
- }
至此,双向通道的流程结束,服务端不仅连接上了通道,而且客户端拿到了服务端STATUS_SUCCESSFUL的消息。
下面用一张图来描述这个过程:
五、消息派发的机制
消息派发的机制其实在上一节的通道建立机制中简单介绍过了,因此接下来的解释就比较容易理解了。
5.1、异步消息派发过程
我们知道,异步消息的派发是通过AsyncChannel的sendMessage()来完成的:
- @AsyncChannelClient.java
- public static void sendMsgToService() {
- sClientAsyncChannel.sendMessage(MainActivity.MSG_ASYNC_REQ);
- }
- @AsyncChannel.java
- public void sendMessage(int what) {
- Message msg = Message.obtain();
- msg.what = what;
- sendMessage(msg);
- }
- public void sendMessage(Message msg) {
- msg.replyTo = mSrcMessenger;
- try {
- //向mDstMessenger发送消息
- mDstMessenger.send(msg);
- } catch (RemoteException e) {
- replyDisconnected(STATUS_SEND_UNSUCCESSFUL);
- }
- }
这个过程与前面4.2节中双向通道建立过程是相同的,其实就是将消息通过AsyncChannel发送给mDstMessenger,也就是远程服务端。
5.2、同步消息派发过程
同步消息的处理其实在前面4.3节中快速双向通道建立流程中介绍过,我们来看一下其流程。
发送同步消息是通过sendMessageSynchronously()方法实现的:- @AsyncChannelClient.java
- public static void sendSyncMsgToService() {
- Message replyMsg = sClientAsyncChannel.sendMessageSynchronously(MainActivity.MSG_SYNC_REQ);
- String msg = (String) replyMsg.obj;
- Log.d(tag, "get service sync reply msg = " + msg);
- }
- @AsyncChannel.java
- public Message sendMessageSynchronously(int what) {
- Message msg = Message.obtain();
- msg.what = what;
- Message resultMsg = sendMessageSynchronously(msg);
- return resultMsg;
- }
- public Message sendMessageSynchronously(Message msg) {
- Message resultMsg = SyncMessenger.sendMessageSynchronously(mDstMessenger, msg);
- return resultMsg;
- }
- private static Message sendMessageSynchronously(Messenger dstMessenger, Message msg) {
- //创建SyncMessenger对象
- SyncMessenger sm = SyncMessenger.obtain();
- try {
- if (dstMessenger != null && msg != null) {
- //将SyncMessenger的Messenger放入消息包中
- msg.replyTo = sm.mMessenger;
- synchronized (sm.mHandler.mLockObject) {
- //将CMD_CHANNEL_FULL_CONNECTION发送给远端的服务
- dstMessenger.send(msg);
- //阻塞监听唤醒
- sm.mHandler.mLockObject.wait();
- }
- } else {
- sm.mHandler.mResultMsg = null;
- }
- } catch (InterruptedException e) {
- sm.mHandler.mResultMsg = null;
- } catch (RemoteException e) {
- sm.mHandler.mResultMsg = null;
- }
- Message resultMsg = sm.mHandler.mResultMsg;
- sm.recycle();
- //将结果返回给客户端
- return resultMsg;
- }
这就是同步消息的传输机制。
- AsyncChannel使用和原理
- AsyncChannel的使用和原理
- AsyncChannel的使用和原理
- AsyncChannel的使用和原理(原)
- AsyncChannel的使用和原理(转载)
- AsyncChannel的使用和原理(原)
- Android StateMachine和AsyncChannel
- Android StateMachine和AsyncChannel
- Android StateMachine和AsyncChannel
- Android StateMachine和AsyncChannel
- Android StateMachine和AsyncChannel
- Android wifi-framework StateMachine和AsyncChannel 学习
- Dll原理和使用
- Dll原理和使用
- DLL 原理和使用
- RapidXml原理和使用
- Dll原理和使用
- RapidXml原理和使用
- kotlin学习(一)kotlin的基本句法语法
- pollard's p-1算法实现(使用GMP库)
- struts2获取请求参数-----属性驱动3种
- 实现文本相似度算法(余弦定理)
- linux中任务调度命令crontab的使用
- AsyncChannel使用和原理
- leetCode刷题归纳-Dynamic Programming( 63. Unique Paths II)
- 【代码积累-1】ActiveObject
- 9、Ubuntu 软件包管理&编程工具
- Tomcat部署项目的几种常见方式
- pydev配置
- windows中的java项目访问虚拟机中的redis
- Android TP驱动之(三)input
- Android新特性介绍,ConstraintLayout完全解析