Android进程间通信(三):使用Messenger实现进程间通信

一 Messenger介绍:

关于进程间的通信:

关于Android进程间的通信,在第一篇文章中我们通过传递Parcel对象,利用IBinder完成了进程间的通信,在第二篇文章 中我们通过在客户端创建一个aidl的文件,在服务端实例化由aapt生成的stub类的对象来完成了进程间的通信。今天我们来使用另一种更简洁的方法—Messenger来实现进程间的通信。

进程之间不能共享内存数据, 但是可以进行通信, 除了简单的Intent通信, 也可以使用Messenger, Messenger基于AIDL实现, 顺序执行, 不支持并发. 为了区分通信的始末, 我们暂定发送数据是客户端, 接收数据是服务端. 本文介绍Messenger的使用方式。

Messenger官方介绍:

Messenger–信使,类的继承关系:

public final class Messenger 
extends Object implements Parcelable   //实现了Parcelable接口

定义:

1 Reference to a Handler,   //一个Messenger关联了一个Handler
2 which others can use to send messages to it. 
3 This allows for the implementation of message-based communication across processes, //基于message的进程间通信
4 by creating a Messenger pointing to a Handler in one process, 
5 and handing that Messenger to another process.

解释为:Messenger引用了一个Handler对象,以便others能够向它发送消息(使用mMessenger.send(Message msg)方法)。该类允许跨进程间基于Message的通信(即两个进程间可以通过Message进行通信),在服务端使用Handler创建一个Messenger,客户端持有这个Messenger就可以与服务端通信了。

以前我们使用Handler+Message的方式进行通信,都是在同一个进程中,从线程持有一个主线程的Handler对象,并向主线程发送消息。

基于消息的进程间通信方式,如图所示:

Android进程间通信(三):使用Messenger实现进程间通信_第1张图片

可以看到,我们可以在客户端发送一个Message给服务端,在服务端的handler中会接收到客户端的消息,然后进行对应的处理,处理完成后,再将结果等数据封装成Message,发送给客户端,客户端的handler中会接收到处理的结果。

二 Handler+Messenger实现进程间的通信,一般使用按如下六个步骤:

(1)创建信使对象:

 远程通过
 serviceMessenger=new Messenger(new ServiceHandler());
 创建一个信使对象

(2)客户端使用bindlerService请求连接远程:

 Intent intent =new Intent(MainActivity.this,MessengerService.class);
        bindService(intent, mConn, Context.BIND_AUTO_CREATE);

(3) 远程onBind方法返回一个bindler:

 @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i("TEST","MessengerService-->onBind()");
        return serviceMessenger.getBinder();
    }

(4) 客户端使用远程返回的bindler得到一个信使(即得到远程信使):

 @Override
        public void onServiceConnected(ComponentName name, IBinder service){
            Log.i("TEST","onServiceConnected()");
            mServiceMessenger = new Messenger(service);
            mTvState.setText("连接成功!");
        }

这里虽然是new了一个Messenger,但我们查看它的实现:

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

发现它的mTarget是通过Aidl得到的,实际上就是远程创建的那个。

(5) 客户端可以使用这个远程信使对象向远程发送消息:

 Message msgFromClient = Message.obtain(null, MSG_SUM);
 mServiceMessenger .send(msgFromClient);

这样远程服务端的Handler对象就能收到消息了,然后可以在其handlerMessage(Message msg)方法中进行处理。(该Handler对象就是第一步服务端创建Messenger时使用的参数ServiceHandler).

经过这5个步骤貌似只有客户端向服务端发送消息,这样的消息传递是单向的,那么如何实现双向传递呢?

(6)首先需要在第5步稍加修改,在mServiceMessenger .send(msgFromClient)前通过

msgFromClient.replyTo = mClientMessenger;

将自己的信使设置到消息中,这样服务端接收到消息时同时也得到了客户端的信使对象mClientMessenger了,然后服务端可以通过/得到客户端的信使对象,并向它发送消息 mClientMessenger= msg.replyTo; mClientMessenger.send(message);

即完成了从服务端向客户端发送消息的功能,这样客服端可以在自己的Handler对象的handlerMessage方法中接收服务端发送来的message进行处理。

双向通信宣告完成。下面来DEMO验证上面的实现双方通信的六个步骤。

三 DEMO实例

DEMO描述

DEMO分为服务端、客户端,实现一个计算三个整数的和。

客户端由普通的MainActivity充当,触发点击事件时,客户端会向服务端发送数据(DEMO中是发送三个整数);服务端由一个MessengerService充当,用于接收客户端发送过来的数据,并求和,然后将求和的结果返回到客户端。最后客户端接收服务端返回的结果,并展示在界面上。

服务端MessengerService.java代码如下:

/**
 * Created by Administrator on 2016/6/23.
 */
public class MessengerService extends Service{

    private static final int MSG_SUM = 0x110;
    private Messenger serviceMessenger;
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("TEST","MessengerService-->onCreate()");
        serviceMessenger=new Messenger(new ServiceHandler());
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i("TEST","MessengerService-->onBind()");
        return serviceMessenger.getBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i("TEST","MessengerService-->onUnbind()");
        return super.onUnbind(intent);
    }
    @Override
    public void onDestroy() {
        Log.i("TEST","MessengerService-->onDestroy()");
        super.onDestroy();
    }

    private static class ServiceHandler extends Handler{
        @Override
        public void handleMessage(Message msgfromClient) {
            Message msgToClient = Message.obtain(msgfromClient);//返回给客户端的消息
            switch (msgfromClient.what){
                //msg 客户端传来的消息
                case MSG_SUM:
                    msgToClient.what = MSG_SUM;
                    try{
                        //模拟耗时
                        Thread.sleep(2000);
                        //msgToClient.arg2 = msgfromClient.arg1 + msgfromClient.arg2;
                        //msgToClient.arg2 = msgfromClient.arg1 + msgfromClient.arg2+(int)(msgfromClient.obj);
                        int arg1=Integer.parseInt(msgfromClient.getData().getString(Constans.ARG1));
                        int arg2=Integer.parseInt(msgfromClient.getData().getString(Constans.ARG2));
                        int arg3=Integer.parseInt(msgfromClient.getData().getString(Constans.ARG3));
                        msgToClient.arg1=arg1;
                        msgToClient.arg2 = arg1 + arg2+arg3;
                        msgfromClient.replyTo.send(msgToClient);
                    } catch (InterruptedException e){
                        e.printStackTrace();
                    } catch (RemoteException e){
                        e.printStackTrace();
                    }
                    break;
            }
            super.handleMessage(msgfromClient);
        }
    }

}

同时在清单文件中注册该服务:

<service android:name=".MessengerService"
            android:process=".remote">service>

客户端MainActivity 代码如下:

public class MainActivity extends AppCompatActivity {

    private static final int MSG_SUM = 0x110;

    //显示连接状态
    private TextView mTvState;
    private Button mBtnAdd;
    private LinearLayout mLyContainer;


    private Messenger mServiceMessenger;
    private Messenger mClientMessenger;

    private int mA;

    private ServiceConnection mConn = new ServiceConnection(){
        @Override
        public void onServiceConnected(ComponentName name, IBinder service){
            Log.i("TEST","onServiceConnected()");
            mServiceMessenger = new Messenger(service);
            mTvState.setText("连接成功!");
        }

        @Override
        public void onServiceDisconnected(ComponentName name){
            mServiceMessenger = null;
            mTvState.setText("disconnected!");
            Log.i("TEST","onServiceDisconnected()");
        }
    };



    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mClientMessenger = new Messenger(new ClientHandler());
        mTvState = (TextView) findViewById(R.id.id_tv_callback);
        mTvState.setText("未连接");

        mBtnAdd = (Button) findViewById(R.id.id_btn_add);
        mLyContainer = (LinearLayout) findViewById(R.id.id_ll_container);
        mBtnAdd.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                if (mServiceMessenger==null){
                    Toast.makeText(MainActivity.this, "服务未连接或者被异常杀死!", Toast.LENGTH_SHORT).show();
                    return;
                }
                performCalculation();
            }
        });
        findViewById(R.id.connect).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                connectService();
            }
        });
        findViewById(R.id.disconnect).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                disconnectService();
            }
        });
    }

    private void performCalculation(){
        try {
            int a = mA++;
            int b = (int) (Math.random() * 100);
            int c = (int) (Math.random() * 100);
            /**创建一个tv,添加到LinearLayout中*/
            TextView tv = new TextView(MainActivity.this);
            tv.setText(a + " + " + b + " + " + c + " = caculating ...");
            tv.setTextSize(20);
            tv.setId(a);
            mLyContainer.addView(tv);
            // Message msgFromClient = Message.obtain(null, MSG_SUM, a, b);
            // Message msgFromClient = Message.obtain(null, MSG_SUM, a, b,c);
            // 这种方式传递参数c会报错,Can't marshal non-Parcelable objects across processes.
            Message msgFromClient = Message.obtain(null, MSG_SUM);
            Bundle data=new Bundle();//Bundle实现了Parcelable接口
            data.putString(Constans.ARG1,String.valueOf(a));
            data.putString(Constans.ARG2,String.valueOf(b));
            data.putString(Constans.ARG3,String.valueOf(c));
            msgFromClient.setData(data);

            msgFromClient.replyTo = mClientMessenger;
            /**往服务端发送消息*/
            mServiceMessenger.send(msgFromClient);
        } catch (RemoteException e){
            e.printStackTrace();
        }
    }

    @Override
    protected void onDestroy(){
        super.onDestroy();
        unbindService(mConn);
    }

    public void connectService(){
        Intent intent =new Intent(MainActivity.this,MessengerService.class);
        bindService(intent, mConn, Context.BIND_AUTO_CREATE);
    }

    public void disconnectService(){
        unbindService(mConn);
        mServiceMessenger=null;
        mTvState.setText("未连接");
    }

    private  class ClientHandler extends Handler{
        @Override
        public void handleMessage(Message msgFromServer){
            switch (msgFromServer.what){
                case MSG_SUM:
                    TextView tv = (TextView) mLyContainer.findViewById(msgFromServer.arg1);
                    tv.setText(tv.getText() + "=>" + msgFromServer.arg2);
                    break;
            }
            super.handleMessage(msgFromServer);
        }
    }
}

方法执行顺序如下:

06-23 17:00:24.490 9869-9869/.remote I/TEST: MessengerService-->onCreate()
06-23 17:00:24.490 9869-9869/.remote I/TEST: MessengerService-->onBind()
06-23 17:00:24.500 9701-9701/com.troy.messengersample I/TEST: onServiceConnected()
06-23 17:00:25.930 9869-9869/.remote I/TEST: MessengerService-->onUnbind()
06-23 17:00:25.930 9869-9869/.remote I/TEST: MessengerService-->onDestroy()

Messenger实现进程通信的流程如下:

Android进程间通信(三):使用Messenger实现进程间通信_第2张图片

最后运行的结果如图:

Android进程间通信(三):使用Messenger实现进程间通信_第3张图片

DEMO总结:

(1)掌握使用Messenger实现进程间的通信;
(2)掌握Messenger通信之间使用Bundle或者Message传输数据;
(3)理解Messenger与Handler之间的关系;
(4)理解Messenger与Binder之间的关系;

学习资料致谢:
1 Android 基于Message的进程间通信 Messenger完全解析
http://blog.csdn.net/lmj623565791/article/details/47017485
2 Android 进程使用 Messenger 通信
http://www.wangchenlong.org/2016/05/17/1605/171-android-messenger/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io

你可能感兴趣的:(Android,进阶)