Android Service更新UI的方法之Messenger
来源:互联网 发布:淘宝ued团队博客 编辑:程序博客网 时间:2024/06/06 08:52
上一篇文章我们讲解了怎样通过AIDL实现Service更新UI的功能,今天要讲的是另外一种方式:Messenger。它可以通过与Handler配合实现不同进程之间的通信,可以跨进程使用Handler发送消息。它的使用不像直接使用AIDL那么复杂,它只需要实现一个Handler对象来处理消息,其他的和使用普通的Service差不多。两个进程间可以通过Messenger来发送Message进行通信,在服务端使用Handler创建一个Messenger,客户端持有这个Messenger就可以与服务端通信了。
我们之前使用Handler和Message都是在同一个进程,子线程持有一个主线程的Handler对象,并向主线程发送消息。Android可以使用Binder机制进行跨进程通信,所以我们当然可以将Handler与Binder结合起来进行跨进程发送消息,Messenger就是基于这个原理。
使用方法:
1、创建一个Handler对象,以它为参数再创建一个Messenger对象
mMessenger = new Messenger(mHandler)
2、客户端使用bindService绑定远程服务
3、远程服务的onBind()方法返回一个Binder对象
return mMessenger.getBinder();
4、客户端使用远程返回的Binder对象得到Messenger对象
public void onServiceConnected(ComponentName name, IBinder service) {
rMessenger = new Messenger(service);
}
5、客户端使用这个Messenger对象向远程发送消息
rMessenger.send(msg);
这样远程服务端的Handler对象就能收到消息,然后在其handleMessage(Message msg)方法中处理消息。
我们已经实现了消息的单向传递,即从客户端向服务端的传递,那么如何实现双向传递呢?
在第5步中,在send(msg)前通过msm.replyTo = mMessenger将自己的Messenger对象设置到消息中,这样服务端接收到消息时同时也得到了客户端的Messenger对象了,然后服务端可以通过客户端的Messenger对象向它发送消息。通过Messenger实现的双向通信就完成了。
下面来看全部的实现代码,首先是Service端:
public class MessengerService extends Service { private Messenger activityMessenger; private MessengerHandler messengerHandler; private int count = 0; private static volatile boolean isRunning; public MessengerService() { messengerHandler = new MessengerHandler(); } @Override public IBinder onBind(Intent intent) { return new Messenger(messengerHandler).getBinder(); } @Override public boolean onUnbind(Intent intent) { isRunning = false; return super.onUnbind(intent); } private class MessengerHandler extends Handler { @Override public void handleMessage(Message msg) { if (msg.replyTo != null) { activityMessenger = msg.replyTo; notifyActivity(); } super.handleMessage(msg); } } private void notifyActivity(){ isRunning = true; new Thread(new Runnable() { @Override public void run() { while(isRunning) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count++; Message message = Message.obtain(); message.arg1 = count; try { activityMessenger.send(message); } catch (RemoteException e) { e.printStackTrace(); } } } }).start(); }}然后是Activity端:
public class ServiceUpdateActivity extends Activity implements View.OnClickListener { private Button btn, btnStop; private TextSwitcher switcher; private int mCount = 0; Intent intent; Messenger mServiceMessenger; Messenger mActivityMessenger; private boolean isMessengerServiceConnected = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_service_update_main); btn = (Button) findViewById(R.id.btn); btnStop = (Button) findViewById(R.id.method_stop); btn.setOnClickListener(this); btnStop.setOnClickListener(this); switcher = (TextSwitcher) findViewById(R.id.number_switcher); switcher.setFactory(new ViewSwitcher.ViewFactory() { @Override public View makeView() { TextView textView = new TextView(ServiceUpdateActivity.this); textView.setGravity(Gravity.CENTER); textView.setTextSize(30); return textView; } }); switcher.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.switcher_text_in)); switcher.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.switcher_text_out)); updateCount(); mActivityMessenger = new Messenger(mMessengerHandler); intent = new Intent(this, MessengerService.class); } @Override protected void onDestroy() { stopAll(); super.onDestroy(); } private void startMessengerMethod() { bindService(intent, messengerServiceConnection, Service.BIND_AUTO_CREATE); } /** * 刷新数字 */ private void updateCount() { //由于从binder调用回来是在子线程里,需要post到主线程调用 new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { switcher.setText(Integer.toString(mCount)); } }); } private void stopAll() { if (isMessengerServiceConnected) { unbindService(messengerServiceConnection); isMessengerServiceConnected = false; } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn: startMessengerMethod(); break; case R.id.method_stop: stopAll(); break; } } //messenger使用 private ServiceConnection messengerServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { isMessengerServiceConnected = true; mServiceMessenger = new Messenger(service); Message message = Message.obtain(); message.replyTo = mActivityMessenger; try { mServiceMessenger.send(message); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; private Handler mMessengerHandler = new Handler() { @Override public void handleMessage(Message msg) { mCount = msg.arg1; updateCount(); super.handleMessage(msg); } };}
上面的代码实现了Activity和Service的双向通信,也就实现了Service更新Activity的UI的功能。可能有的同学会觉得奇怪,Messenger是怎么做到跨进程发送消息的。
首先来看一个问题 ,在Service中的onBind()方法中,返回了一个Messenger对象,
@Override public IBinder onBind(Intent intent) { return new Messenger(messengerHandler).getBinder(); }而在Activity中的onServiceConnected方法中,却new了一个新的Messenger对象,那就奇怪了,两个不同的对象怎么做到通信的?
<span style="white-space:pre"></span>@Override public void onServiceConnected(ComponentName name, IBinder service) { mServiceMessenger = new Messenger(service); Message message = Message.obtain(); message.replyTo = mActivityMessenger; try { mServiceMessenger.send(message); } catch (RemoteException e) { e.printStackTrace(); } }我们看一下Messenger的构造函数,还是首先看看Service端,
public Messenger(Handler target) { mTarget = target.getIMessenger(); }其中mTarget是一个IMessenger的aidl接口,getIMessenger()做了什么呢
final IMessenger getIMessenger() { synchronized (mQueue) { if (mMessenger != null) { return mMessenger; } mMessenger = new MessengerImpl(); return mMessenger; } } private final class MessengerImpl extends IMessenger.Stub { public void send(Message msg) { msg.sendingUid = Binder.getCallingUid(); Handler.this.sendMessage(msg); } }可以看到getIMessenger()返回了一个IMessenger类型的Binder对象,Messenger本身也是通过AIDL实现的。而且我们在调用send(msg)方法的时候,其实是调用了与这个Binder关联的Handler的sendMessage()方法,继而会触发这个Handler的handleMessage()的调用。
通过上面的分析,大概能猜出来,Activity端就是拿到这个IMessenger类型的Binder的代理对象,通过代理对象的send()方法来发送消息到Service中。
public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target); }至此,关于跨进程的Service通知Activity更新UI的分析就讲完了,可以发现无论是哪种实现,最终都是通过AIDL的方式,只是做了不同的封装和处理罢了。也说明实现一个问题的方式有很多,但也许表面上看起来不同的实现,底层的原理都是相似的。
点我下载Demo源代码
- Android Service更新UI的方法之Messenger
- Android Service更新UI的方法之AIDL
- Android Service 通知Activity更新界面的方法研究|Service通过Broadcast更新UI
- Android Service 通知Activity更新界面的方法研究|Service通过Broadcast更新UI
- Android Service 通知Activity更新界面的方法研究|Service通过Broadcast更新UI
- Android Service 之(Bind Service,使用 Messenger)
- Android 绑定Service的实现方法二:使用Messenger
- Android更新UI的方法
- android更新UI的方法
- Android更新ui的方法
- Android Service IPC通信之Messenger机制
- Android开发之通过Handler的post方法更新UI
- android 之 Handler 详解----(三)更新UI的方法
- android UI(内容)更新的方法之handler、runOnUiThread()
- android service 更新widget UI
- Android Service 之三(Bind Service,使用 Messenger)
- Android Service 之三(Bind Service,使用 Messenger)
- Android的的WhatsApp Messenger的更新
- Leetcode Range Sum Query 2D - Immutable
- Julia : 1亿条记录读取测试,及几个优化点
- 从理论到实践,全方位认识DNS(实践篇)
- Linux环境下开发Android小技巧
- Android 打包Jar(发布SDK)常见问题及解决方案
- Android Service更新UI的方法之Messenger
- 《java》笔记<五>
- jQuery知识汇总
- HDOJ--1010
- String 中 的indexOf()
- 使用Kinect 进行图片浏览
- Homebrew是啥
- 多核处理器
- 计时器(销毁后的时间也计算)