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

来源:互联网 发布:yii2连接多个数据库 编辑:程序博客网 时间:2024/06/04 17:50

一 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关联了一个Handler2 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对象,并向主线程发送消息。

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

这里写图片描述

可以看到,我们可以在客户端发送一个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实现进程通信的流程如下:

这里写图片描述

最后运行的结果如图:

这里写图片描述

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

0 0