Android中使用 Messenger 实现进程间通信小案例与分析说明

Coral ·
更新时间:2024-11-13
· 993 次阅读

文章目录Messenger 是什么Messenger 底层实现Messenger 使用说明案例实现说明新建一个项目创建 ServiceService 代码说明客户端代码说明小结验证结果Messenger 工作原理总结 Messenger 是什么

Messenger 可以翻译为信使,顾名思义,通过它可以实现在不同进程中传递 Message 对象,在 Message 中可以携带我们需要传递的数据,借此就可以实现数据在不同进程间的通信。

Messenger 底层实现

Messenger 是一种轻量级的 IPC 方案,它的底层实现是 AIDL ,这块同学们可以通过看 Messenger 这个类的源码中的构造方法得知。

Messenger 使用说明

Messenger的使用会相对简单,它对 AIDL 做了封装,使得我们可以更便捷的进行进程间通信。
同时,由于它一次处理一个请求,因此服务端我们不用考虑线程同步的问题,这是因为服务端此时不存在并发执行的情形。

案例实现 说明

案例只用到了一个应用,首先是一个 Activity,把Activity 里的代码当作客户端的代码,后面统称客户端;服务端我们用一个 Service 组件(后面统称服务端)来实现,然后通过客户端和 Service 绑定来启动服务端,进而模拟实现客户端和服务端的通信。

同学们这时候有疑问了?

你这不是在同一个进程吗?不急往下看。

这里我们创建好 Service 后,会另外在清单配置文件中给 Service 组件添加一个 process 属性,用来使 Service 组件运行在另一个进程。这样就可以在一个应用中模拟两个进程的运行了,也方便demo的实现。

至于组件的 process 属性,同学们自行查阅资料学习,这里不细说了。

清单配置文件如下图示:

在这里插入图片描述

新建一个项目

新建操作,我就不给出了,同学们自己完成。

创建 Service

项目新建完成后,带有一个 Activity ,我们就当作客户端用,然后再创建一个 Service,命名为 MessengerService.java ,如下图示:

在这里插入图片描述
在这里插入图片描述

这里只用到了 3 个类,其中 MyConstant.java 的代码如下图示:

在这里插入图片描述
别忘记在清单配置文件中给 MessengerService 这个服务配置 process 属性,如下图示:

在这里插入图片描述

到这里我们就拥有了客户端和服务端了。

Service 代码说明

首先给出代码,如下:

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 组件的进程

切换到 activity 进程打印窗口查看,如下:

在这里插入图片描述
上面说明客户端已经接收到了服务端回复的消息

到这里就完成了使用 Messenger 实现进程间通信的小案例,希望对同学们有所帮助。 Messenger 工作原理 总结

这里再次强调,之所以选择在同一个应用内进行进程间通信,是因为操作起来方便,方便,方便。但是效果和在两个应用间进行进程间通信时一样的。

还有一点大家需要知道:同一个应用的不同组件,如果它们运行在不同进程中,那么和它们分别属于两个应用没有本质区别。


作者:邹奇



messenger 进程 进程间通信 通信 Android

需要 登录 后方可回复, 如果你还没有账号请 注册新账号