基于Message的进程间通信实例

本文深入探讨基于Message的进程间通信机制,详细解释了如何利用Messenger接口和Handler类实现跨进程消息传递,并通过实例展示了创建Messenger对象、建立通信线路及双向通信的过程。

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

一. 概述

   前面已经讨论过基于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() {
		@Override
		public 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() {
	}

	@Override
	public 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;
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.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);
			}
		});

	}

	@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		super.onPause();

		this.unbindService(mConnection);

	}

	@Override
	protected void onStart() {
		// TODO Auto-generated method stub
		super.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>

完。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值