Android Service (Bind Service,使用 Messenger)

本文介绍了如何在Android应用中使用Messenger实现进程间通信。通过客户端和服务端的交互,展示了如何在不同进程间进行消息传递。包括客户端创建Handler、生成Messenger、发送消息,以及服务端接收消息并响应的过程。实例通过两个工程演示了这种通信方式的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://www.apkbus.com/android-13768-1-1.html

上次讲了第一种 Bind Service 的实现方式,今天讲
第二种:使用 Messenger
这种情况适用于你想实现进程间通信的场合,它分以下几个步骤:
① service 内部需要有一个 Handler 的实现,它被用来处理从每一个 client 发送过的来请求
② 通过这个 Handler ,来生成一个 Messenger
③ 在 service 的onBind() 方法中,需要向 client 返回由该 Messenger 生成的一个 IBinder 实例
④ client 使用从 service 返回的 IBinder 实例来初始化一个 Messenger, 然后使用该 Messenger 与 service 进行通信
⑤ service 通过它自身内部的 Handler 实现(Handler 人 handleMessage() 方法中)来处理从 client 发送过来的请求

下面给出一实例进行说明,该实现由两个工程组成:
① BindServiceDemo_Client: 该工程中只包含一个Activity,用来绑定另一个工程中的 Service
② BindServiceDemo_Service:该工程中只包含一个Service
在实例中, Client 与 Service 中都有一个Messenger ,所以可以进行两者的互相请求与应答。话不多说,贴上部分源码:
① BindServiceDemoClient 中: 
Java代码

  1. // client 端 Handler 的实现
  2. private class IncomingHandler extends Handler {
  3.                 /*
  4.                  * 处理从Service发送至该Activity的消息
  5.                  * (non-Javadoc)
  6.                  * @see android.os.Handler#handleMessage(android.os.Message)
  7.                  */
  8.                 @Override
  9.                 public void handleMessage(Message msg) {
  10.                         switch (msg.what) {
  11.                                 case MSG_SET_VALUE:
  12.                                         Toast.makeText(BindServiceDemoClient.this,
  13.                                                         "set value as: " + msg.arg1, Toast.LENGTH_SHORT)
  14.                                                         .show();
  15.                                         break;
  16.                                 default:
  17.                                         super.handleMessage(msg);
  18.                         }
  19.                 }
  20.         }
复制代码



Java代码
  1. // client 端 ServiceConnection 的实现
  2. private ServiceConnection myRemoteServiceConnection = new ServiceConnection() {
  3.                 public void onServiceConnected(android.content.ComponentName name,
  4.                                 android.os.IBinder service) {
  5.                         updateLog("myServiceConnection.onServiceConnected");
  6.                         // 客户端 与 服务 不在同一个进程中的话,所以不可以进行显示强制类型转换的,
  7.                         // 因为,通过Debug,可以发现此时传进来的 Service 的类型是 BinderProxy
  8.                         isBound = true;
  9.                         // 使用从Service返回的IBinder来生成一个Messenger
  10.                         Messenger serviceMessenger = new Messenger(service);
  11.                         // 生成一个Message
  12.                         Message msg = Message.obtain();
  13.                         msg.what = MSG_REGISTER_CLIENT;
  14.                         msg.replyTo = messenger;
  15.                         try {
  16.                                 // 向Service 发送Message
  17.                                 serviceMessenger.send(msg);
  18.                         } catch (RemoteException e) {
  19.                                 e.printStackTrace();
  20.                         }

  21.                         msg = Message.obtain();
  22.                         msg.what = MSG_SET_VALUE;
  23.                         msg.replyTo = messenger;
  24.                         msg.arg1 = 10;
  25.                         try {
  26.                                 serviceMessenger.send(msg);
  27.                         } catch (RemoteException e) {
  28.                                 e.printStackTrace();
  29.                         }
  30.                 };
复制代码
② BindServiceDemoService 中:
Java代码

  1. // service 端的 Handler 的实现
  2. private class IncomingHandler extends Handler {

  3.                 @Override
  4.                 public void handleMessage(Message msg) {
  5.                         switch (msg.what) {
  6.                                 case MSG_REGISTER_CLIENT:
  7.                                         allClients.add(msg.replyTo);
  8.                                         break;
  9.                                 case MSG_UNREGISTER_CLIENT:
  10.                                         allClients.remove(msg.replyTo);
  11.                                         break;
  12.                                 case MSG_SET_VALUE:
  13.                                         int value = msg.arg1;
  14.                                         for (int i = 0; i < allClients.size(); i++) {
  15.                                                 try {
  16.                                                         allClients.get(i).send(
  17.                                                                         Message.obtain(null, MSG_SET_VALUE, value,
  18.                                                                                         0));
  19.                                                 } catch (RemoteException e) {
  20.                                                         allClients.remove(i);
  21.                                                 }
  22.                                         }
  23.                                         break;
  24.                                 default:
  25.                                         super.handleMessage(msg);
  26.                         }
  27.                 }

  28.         }
复制代码





Java代码
  1. @Override
  2. public IBinder onBind(Intent intent) {
  3.     return messenger.getBinder();
  4. }
复制代码


下面来看运行效果图(Debug模式):
首先,启动 BindServiceDemoClient

1.jpg 
此时,所有的进程如下:

2.jpg 
最下面的那个进程即为 BindServiceDemoClient 工程对应的进程,而且还没有 BindServiceDemoService 工程的进程。下面,点击 "Bind Service" 的按钮,当执行下图中的断点时,请注意右上角 service 的类型(BindProxy),这也从一个方面说明了为什么在 IPC 的时候不可以使用 IBinder 来实现。


按F8继续执行,会得到如下截图:

4.jpg 
  
此时,再来看一下系统中的进程情况:

5.jpg 
会发现,在最下面多了一个 BindServiceDemoService 工程的进程,这就说明了 client 与 service 是在不同的进程内的,这也正是本例子的意图:使用 Messenger 在不同进程间进行通信。

现在通过 DDMS 控制台,直接将 com.archer.rainbow.service 进程杀掉,来模拟系统资源少而急需回收系统资源的情况,如下:

6.jpg 
系统会输出如下日志:

7.jpg 
之后,当系统资源充足的时候,会自己重新启动该进程,如下图:

8.jpg 
同时,系统输出的日志为:


另外,需要注意的是,当我们通过界面点击 "Unbind Service" 的时候,虽然服务被解绑了,但是系统并没有立即将 com.archer.rainbow.service 这一进程给杀掉:

10.jpg 

11.jpg 
但若此时,通过 DDMS 控制台,直接将该进程杀掉的话,系统也不会重新启动该进程

12.jpg 



注意与上面对应的日志
进行比对,你会发现它少了 "Scheduling restart........" 的这条日志。

PS:若想将 service 在另一个进程中启动,你也可以在声明 Service 的时候,使用 "android:process=":remote"" 这种方式来实现。


 BindServiceDemo_Client.zip (54.33 KB, 下载次数: 13) 

 BindServiceDemo_Service.zip (43.93 KB, 下载次数: 11) 



13.jpg (9.54 KB, 下载次数: 2)

13.jpg

9.jpg (12.5 KB, 下载次数: 2)

9.jpg

2.jpg (67.31 KB, 下载次数: 2)

2.jpg


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值