(写在开头:本文转自CSDN 山庄来客,觉得文章写得很好故转载到简书,原始文章链接已在下面贴出,感谢作者的无私奉献,如有侵权或者其他问题,请及时联系本人)
原文作者信息:
作者:山庄来客
来源:CSDN
原文:https://blog.csdn.net/fuyajun01/article/details/39997887/
版权声明:本文为博主原创文章,转载请附上博文链接!
一. 概述
前面已经讨论过基于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对象。进程间消息通信的本质是:
-
Messenger类实现了Parcelable接口,它可以通过Binder通信从一个进程发送到另一个进程。
-
一方面,Messenger类通过构造函数,传入了一个Handler对象,通过Handler类提供的getIMessenger()方法,持有了与关联的Handler对象的sendMessenge方法的通路,即通过Messenger的send方法发送消息时,实际上会调用与之关联的Handler对象的sendMessage方法。
-
另一方面,为了建立与另一方的通信,需要借助如下构建函数打通与另一方的通信线路
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
这样就建立一个Binder通信线路。 -
通过这条Binder通信线程,即借助上述所说的构造函数创建的Messenger对象,将Message发送到Binder通信的另一方。这个Messenger对象所关联的Handler对象其实是在另一个进程中。所以,它通过该对象调用send方法,实质上就是调用与之关联的Handler对象的sendMessage方法,从面可以在对应的handleMessage方法中处理发送过来的消息。这样就实现了一方通信,即从本进程向另一个进程中发送了一个Message。
-
接下来,另一个进程处理收到的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>
完。
网友评论