赞
踩
Messenger 可以翻译为信使,顾名思义,通过它可以实现在不同进程中传递 Message 对象,在 Message 中可以携带我们需要传递的数据,借此就可以实现数据在不同进程间的通信。
Messenger 是一种轻量级的 IPC 方案,它的底层实现是 AIDL ,这块同学们可以通过看 Messenger 这个类的源码中的构造方法得知。
Messenger的使用会相对简单,它对 AIDL 做了封装,使得我们可以更便捷的进行进程间通信。
同时,由于它一次处理一个请求,因此服务端我们不用考虑线程同步的问题,这是因为服务端此时不存在并发执行的情形。
案例只用到了一个应用,首先是一个 Activity,把Activity 里的代码当作客户端的代码,后面统称客户端;服务端我们用一个 Service 组件(后面统称服务端)来实现,然后通过客户端和 Service 绑定来启动服务端,进而模拟实现客户端和服务端的通信。
同学们这时候有疑问了?
你这不是在同一个进程吗?不急往下看。
这里我们创建好 Service 后,会另外在清单配置文件中给 Service 组件添加一个 process 属性,用来使 Service 组件运行在另一个进程。这样就可以在一个应用中模拟两个进程的运行了,也方便demo的实现。
至于组件的 process 属性,同学们自行查阅资料学习,这里不细说了。
清单配置文件如下图示:
新建操作,我就不给出了,同学们自己完成。
项目新建完成后,带有一个 Activity ,我们就当作客户端用,然后再创建一个 Service,命名为 MessengerService.java ,如下图示:
这里只用到了 3 个类,其中 MyConstant.java 的代码如下图示:
别忘记在清单配置文件中给 MessengerService 这个服务配置 process 属性,如下图示:
到这里我们就拥有了客户端和服务端了。
首先给出代码,如下:
package com.example.messengerdemo.service; import android.app.Service; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.util.Log; import com.example.messengerdemo.constant.MyConstant; public class MessengerService extends Service { private static final String TAG = "MessengerService"; public MessengerService() { } private static class MessengerHandler extends Handler{ @Override public void handleMessage(Message msg) { switch (msg.what){ case MyConstant.MSG_FROM_CLIENT: // 接收客户端发来的消息并打印 Log.e(TAG, "receive msg from client:" + msg.getData().getString(MyConstant.MSG)); // 获取客户端的 Messenger 对象,用来回复客户端消息 Messenger clientMessenger = msg.replyTo; Message replyMessage = Message.obtain(null, MyConstant.MSG_FROM_SERVER); Bundle bundle = new Bundle(); bundle.putString(MyConstant.REPLY, "消息已经收到,稍后回复你。"); replyMessage.setData(bundle); try { clientMessenger.send(replyMessage);// 回复客户端:服务端我已经接收消息 } catch (RemoteException e) { e.printStackTrace(); } break; } } } // 创建 Messenger 对象,作用是将客户端的发送的消息传递给 MessengerHandler 处理 private final Messenger messenger = new Messenger(new MessengerHandler()); @Override public IBinder onBind(Intent intent) { // 服务端返回 Messenger 对象底层的 binder return messenger.getBinder(); } }
首先,我们创建一个服务端的 Handler,这里命名为 MessengerHandler 继承 Handler,然后重写 handleMessage() 方法来处理客户端发来的消息,如下图示:
那么消息怎么传递给 MessengerHandler 呢,我们就要用到 Messenger 对象了,所以需要创建一个 Messenger 对象,如下图示:
然后你在客户端需要获取到服务端的 Messenger 对象,这样才能给服务端发消息,所以还需要在 onBind() 方法中返回服务端 Messenger 对象底层的 binder,如下图示:
所以我们到这里就可以知道,创建一个 Messenger 对象,他的构造方法里的参数既可以是 Handler 类型参数,也可以是 IBinder 类型的参数,这里通过看类的源码的构造方法可以看出,如下图示:
首先给出 activity 中的代码,如下:
package com.example.messengerdemo.activity; import androidx.appcompat.app.AppCompatActivity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.util.Log; import android.view.View; import com.example.messengerdemo.R; import com.example.messengerdemo.constant.MyConstant; import com.example.messengerdemo.service.MessengerService; public class MainActivity extends AppCompatActivity{ // 服务端通过获取客户端的 Messenger 对象 回复消息给客户端 所以客户端也需要声明这么一个 Messenger 对象 private Messenger getReplyMessenger = new Messenger(new MessengerHandle()); private static class MessengerHandle extends Handler{ @Override public void handleMessage(Message msg) { switch (msg.what){ case MyConstant.MSG_FROM_SERVER: Log.e("TAG", "receive msg from server:" + msg.getData().getString(MyConstant.REPLY)); break; } } } private Messenger messenger = null;// 声明 Messenger 对象,初始化获取服务端的Messenger对象用 // 创建 ServiceConnection 对象 private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { messenger = new Messenger(iBinder);// 通过服务端返回的 binder 创建 Messenger 对象 // 创建Message对象并设置携带的数据 Message message = Message.obtain(null, MyConstant.MSG_FROM_CLIENT); Bundle bundle = new Bundle(); bundle.putString(MyConstant.MSG, "imxiaoqi, enjoy coding."); message.setData(bundle); message.replyTo = getReplyMessenger;// 保证服务端处理消息的时候,能获取到客户端的Messenger对象 try { messenger.send(message);// 通过服务端的Messenger对象发送消息给服务端 } catch (RemoteException e) { e.printStackTrace(); } } // 在正常情况下该方法是不被调用的,它的调用时机是当Service服务被异外销毁时,权例如内存的资源不足时 @Override public void onServiceDisconnected(ComponentName componentName) { Log.e("TAG", "MainActivity onServiceDisconnected callback"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 绑定服务,开启了新的服务进程(后面统一称服务端) Intent intent = new Intent(MainActivity.this, MessengerService.class); bindService(intent, connection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); // 活动销毁,记得解绑服务 unbindService(connection); } }
在onCreate() 方法中,我们绑定服务开启服务端进程,如下图示:
onDestory() 方法就是正常的解绑服务的操作,没什么好说的;
这里同学们应该有注意到,绑定服务的代码中有一个 connection 参数,这个参数其实一个 ServiceConnection 对象,所以我们还需要创建一个 ServiceConnection 对象,这个对象的作用是用来获取服务端的 Messenger 对象并给服务端发送消息,这些操作是在 onServiceConnected() 方法中实现,正常通过绑定方式启动服务并建立连接后,会回调该方法,如下图示:
上图中创建 Message 对象并设置携带的数据以及通过服务端的 Messenger 对象发送消息给服务端大家都比较好理解。
但是有一行代码可能同学们会存在疑惑,就是
message.replyTo = getReplyMessenger;// 保证服务端处理消息的时候,能获取到客户端的Messenger对象
。其实这行代码的作用是:为了在发给服务端的消息中携带客户端的 Messenger 对象,这样服务端就可以通过 message(客户端发来的) 获取客户端的 Messenger 对象,也就能使用这个对象回复消息给客户端说我已经接收到你的消息了。
所以,如果服务端需要回复消息给客户端,那么我们的客户端肯定也是需要有一个 Messenger 对象和 一个 Handler 对象的,只有存在这两个对象才可以接收到服务端的消息并作处理,如下图示:
服务端获取客户端的 Messenger 对象代码,如下图示:
到这里代码就全部完成,我们来梳理一下上面都做了什么操作,可以实现什么功能?
我们在一个应用中模拟了客户端和服务端,并运行在不同进程;然后客户端可以发消息给服务端,服务端接收到消息并处理消息,log打印客户端消息;同时服务端收到消息后,再回应客户端说我已经接收到你发给我的消息了,这时候我们在客户端接收到消息并处理后,也用log打印服务端回复的消息。
我这里连接到了自己的手机,运行应用测试,我们来看一下。
usb连接手机,点击按钮运行应用:
运行成功后打开 logcat 窗口查看日志:
上图说明服务端已经接收到客户端的消息并做了打印
com.example.messengerdemo
这个对应 activity 的进程,com.example.messengerdemo:remote
这个对应 service 组件的进程
上面说明客户端已经接收到了服务端回复的消息
这里再次强调,之所以选择在同一个应用内进行进程间通信,是因为操作起来方便,方便,方便。但是效果和在两个应用间进行进程间通信时一样的。
还有一点大家需要知道:同一个应用的不同组件,如果它们运行在不同进程中,那么和它们分别属于两个应用没有本质区别。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。