基于Message的进程间通信实例

来源:互联网 发布:mac翻墙用什么软件好 编辑:程序博客网 时间:2024/05/16 17:58

一. 概述

   前面已经讨论过基于message的线程间通信,通过Handler类来处理,实际上,跨进程的Messasge通信也是可以的。在Handler类中,有如下定义:

   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) {            Handler.this.sendMessage(msg);        }    }

这里我们关注的是IMessenger接口,它的定义如下:

package android.os;import android.os.Message;/** @hide */oneway interface IMessenger {    void send(in Message msg);}

可以看到,定义了一个发送消息的接口。从MessengerImpl的实现来看,实现发送消息是通过与之关联的Handler来发送的。一个Messenger会关联一个Handler对象。进程间消息通信的本质是:

1. Messenger类实现了Parcelable接口,它可以通过Binder通信从一个进程发送到另一个进程。

2. 一方面,Messenger类通过构造函数,传入了一个Handler对象,通过Handler类提供的getIMessenger()方法,持有了与关联的Handler对象的sendMessenge方法的通路,即通过Messenger的send方法发送消息时,实际上会调用与之关联的Handler对象的sendMessage方法。

3. 另一方面,为了建立与另一方的通信,需要借助如下构建函数打通与另一方的通信线路

    public Messenger(IBinder target) {        mTarget = IMessenger.Stub.asInterface(target);    }

这样就建立一个Binder通信线路。

4. 通过这条Binder通信线程,即借助上述所说的构造函数创建的Messenger对象,将Message发送到Binder通信的另一方。这个Messenger对象所关联的Handler对象其实是在另一个进程中。所以,它通过该对象调用send方法,实质上就是调用与之关联的Handler对象的sendMessage方法,从面可以在对应的handleMessage方法中处理发送过来的消息。这样就实现了一方通信,即从本进程向另一个进程中发送了一个Message。

5. 接下来,另一个进程处理收到的Message,进行解析,做些处理后,又通过Message对象携带的Messagener对象(Message.replyTo),向本进程发送回一个Message消息,至此,完成了一次双向通信。

使用如下图示说明如下:


二、实例分析

如上所述,要实现基于Message的进程间通信,至少要创建三个Messenger对象,其中两个Messenger对象会传入Handler对象,另一个Messenger对象则用于建立Binder通信线路,会传入一个IBinder对象。

如下 所示,我们创建了MessengerService类,它将作为通信的一方:

public class MessengerService extends Service {private final Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {Message reply = Message.obtain();reply.copyFrom(msg);try {System.out.println("receive handler call from remote...");System.out.println("ARG1: " + msg.arg1);System.out.println("ARG2: " + msg.arg2);msg.replyTo.send(reply);} catch (RemoteException e) {}}};private final Messenger mMessenger = new Messenger(mHandler);public MessengerService() {}@Overridepublic IBinder onBind(Intent intent) {return mMessenger.getBinder();}}

特别留意的是它重载了onBind方法,通过此方法,服务的调用者就建立了与本地mMessgenger通信的一条线程。

在通信的另一方,我们的定义如下:

public class MessengerTest extends Activity {private Messenger mServiceMessenger;private ServiceConnection mConnection = new ServiceConnection() {public void onServiceConnected(ComponentName name, IBinder service) {synchronized (MessengerTest.this) {mServiceMessenger = new Messenger(service);// MessengerTest.this.notifyAll();}}public void onServiceDisconnected(ComponentName name) {mServiceMessenger = null;}};@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.hello);Button btn = (Button) findViewById(R.id.btn);btn.setOnClickListener(new OnClickListener() {public void onClick(View v) {// TODO Auto-generated method stub(new TestThread()).doTest(1000);}});}@Overrideprotected void onPause() {// TODO Auto-generated method stubsuper.onPause();this.unbindService(mConnection);}@Overrideprotected void onStart() {// TODO Auto-generated method stubsuper.onStart();this.bindService(new Intent(MessengerTest.this, MessengerService.class),mConnection, Context.BIND_AUTO_CREATE);}private class TestThread extends TestHandlerThread {private Handler mTestHandler;private Messenger mTestMessenger;public void go() {synchronized (MessengerTest.this) {mTestHandler = new Handler() {public void handleMessage(Message msg) {TestThread.this.handleMessage(msg);}};mTestMessenger = new Messenger(mTestHandler);TestThread.this.executeTest();}}public void executeTest() {Message msg = Message.obtain();msg.arg1 = 100;msg.arg2 = 1000;msg.replyTo = mTestMessenger;try {mServiceMessenger.send(msg);} catch (RemoteException e) {}}public void handleMessage(Message msg) {if (msg.arg1 != 100) {failure(new RuntimeException("Message.arg1 is not 100: "+ msg.arg1));return;}if (msg.arg2 != 1000) {failure(new RuntimeException("Message.arg2 is not 1000: "+ msg.arg2));return;}if (!mTestMessenger.equals(msg.replyTo)) {failure(new RuntimeException("Message.replyTo is not me: "+ msg.replyTo));return;}success();}};}

我们在创建mConnectioin对象时,在onServiceconnected方法里,创建了mServiceMessenger,它将作为信使,将本进程发送的消息传递给另一方。

本地创建的Messenger对象是mTestMessager.

测试程序如下的代码如下所示:

abstract class TestHandlerThread {private boolean mDone = false;private boolean mSuccess = false;private RuntimeException mFailure = null;private Looper mLooper;public abstract void go();public TestHandlerThread() {}public void doTest(long timeout) {(new LooperThread()).start();synchronized (this) {long now = System.currentTimeMillis();long endTime = now + timeout;while (!mDone && now < endTime) {try {wait(endTime - now);} catch (InterruptedException e) {}now = System.currentTimeMillis();}}mLooper.quit();if (!mDone) {throw new RuntimeException("test timed out");}if (!mSuccess) {throw mFailure;}}public Looper getLooper() {return mLooper;}public void success() {synchronized (this) {mSuccess = true;quit();}}public void failure(RuntimeException failure) {synchronized (this) {mSuccess = false;mFailure = failure;quit();}}class LooperThread extends Thread {public void run() {Looper.prepare();mLooper = Looper.myLooper();go();Looper.loop();synchronized (TestHandlerThread.this) {mDone = true;if (!mSuccess && mFailure == null) {mFailure = new RuntimeException("no failure exception set");}TestHandlerThread.this.notifyAll();}}}private void quit() {synchronized (this) {mDone = true;notifyAll();}}}

为了演示跨进程通信,我们将service在另一个进程中启动:

在AndroidManifest.txml中加入如下声明:

         <service            android:name=".messagetest.MessengerService"            android:process=":remote" >            <intent-filter>                <action android:name="com.fyj.demo.messagetest.MessengerService" />            </intent-filter>        </service>

完。



1 0
原创粉丝点击