Android应用开发那些事

基于Message的进程间通信实例

2019-04-29  本文已影响2人  洛的俠

(写在开头:本文转自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对象。进程间消息通信的本质是:

  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>

完。

上一篇 下一篇

猜你喜欢

热点阅读