跨进程通讯之Messenger

1.简介
Messenger,顾名思义即为信使,经过它能够在不一样进程中传递Message对象,经过在Message中放入咱们须要的入局,就能够轻松实现数据的跨进程传递了。Messenger是一种轻量级的IPC方案,其底层实现是AIDL。
Messenger的使用方法很简单,它对AIDL进程了封装,而且因为它一次只处理一个请求,所以在服务端咱们不须要考虑同步的问题。
 
2.实现跨进程通讯
1)服务端进程
首先咱们须要在服务端建立一个Service来处理客户端的链接请求,同时建立一个Handler并经过它来建立一个Messenger对象。而后在Service的onBind方法中返回这Messenger对象底层的Binder便可。
2)客户端进程
客户端进程中,首先须要绑定服务端的Service,绑定成功后用服务端返回的IBinder对象建立一个Messenger,并经过这个Messenger对象向服务端发送Message。此外,若是须要服务端响应客户端,咱们就须要像服务端那样建立一个Handler并建立一个新的Messenger,并把这个Messenger对象经过Message的replyTo参数传递给服务器,服务器就能够经过这个replyTo参数回应客户端了。
 
     Messenger因为是在AIDL上进行了封装,其使用过程相对比较简单,下面的示例实现了客户端发送消息给服务端,服务端会根据客户端发送的消息予以回复并将回复的结果显示在客户端上。
3)下面直接贴上client和service的代码,最后附上运行结果。
Client:
package com.pignet.messengerdemo2;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private  static  TextView tvMsgFromService;
    Button btnSend;
    EditText etClient;


    private Messenger mService;

    private Messenger mGetReplyFromService =new Messenger(new MessengerHandler());
    private static class MessengerHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 1:
                    tvMsgFromService.setText(msg.getData().getString("reply"));
                    break;


            }
            super.handleMessage(msg);
        }
    }
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mService=new Messenger(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {


        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnSend= (Button) findViewById(R.id.btn_send);
        etClient= (EditText) findViewById(R.id.et_client);
        tvMsgFromService = (TextView) findViewById(R.id.tv_msg_from_service);
        Intent intent= new Intent(MainActivity.this,MessengerService.class);
        bindService(intent,mConnection, Context.BIND_AUTO_CREATE);

        btnSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String msgFromClient;
                Message msg = Message.obtain(null,0);
                Bundle data = new Bundle();
                if((msgFromClient=String.valueOf(etClient.getText()))==null){
                    Toast.makeText(MainActivity.this,"The Message is null",Toast.LENGTH_SHORT).show();
                }else{
                    data.putString("msg", msgFromClient);
                    msg.setData(data);
                    msg.replyTo= mGetReplyFromService;
                    try {
                        mService.send(msg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }

            }
        });


    }

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

 

Service:
package com.pignet.messengerdemo2;

import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;

/**
 * Created by DB on 2017/7/2.
 */

public class MessengerService extends Service {
    private static final String TAG="MessengerService";

    private static  class  MessengerHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {

            switch (msg.what){
                case 0:
                    Log.i(TAG, "receive msg from client: "+msg.getData().getString("msg"));
                    Messenger mService = msg.replyTo;
                    Message replyMessage = Message.obtain(null,1);
                    Bundle bundle = new Bundle();
                    bundle.putString("reply","您的信息"+msg.getData().getString("msg")+"已收到,稍后会有回复");
                    replyMessage.setData(bundle);
                    try{
                        mService.send(replyMessage);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
            }
            super.handleMessage(msg);
        }
    }

    private final Messenger mMessenger = new Messenger(new MessengerHandler());
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }
}

 

 
这里为了模拟不一样应用间的跨进程通讯,将Service类运行在了与Client不一样的进程中,这样就能够实现和不一样应用间通讯同样的效果。
因此咱们须要在manifests文件中加入:
<service android:name=".MessengerService"
    android:process=":romote">
</service>

运行结果以下java

 

 
 
3.Messenger源码浅析:
     进入到Messenger源码后,查看它的结构
Messenger类有两个构造函数,分别是能够用Handler和IBinder实现,这也是咱们以前实现跨进程中通讯中实例化Messenger类中已经用到的两种构造函数。
public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }
public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);
    }

由于以前提到过Messenger的底层实现是AIDL,因此这边我看这个IMessage和那个IBookManager有的相似,点开后发现确实如此android

public interface IMessenger extends android.os.IInterface {
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements
            android.os.IMessenger {
        private static final java.lang.String DESCRIPTOR = "android.os.IMessenger";

        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        public static android.os.IMessenger asInterface(...}

        public android.os.IBinder asBinder() {
            return this;
        }

        @Override
        public boolean onTransact(int code, android.os.Parcel data,
                android.os.Parcel reply, int flags)
                throws android.os.RemoteException {...}

        private static class Proxy implements android.os.IMessenger {...}

    public void send(android.os.Message msg)
            throws android.os.RemoteException;
}

以前咱们为BookManager类定义的方法是一个addBook和getBookList,而这边咱们发现Messenger对AIDL的封装中加入的是一个send方法。服务器

那这个方法是在哪里实现的呢。app

private final class MessengerImpl extends IMessenger.Stub {
        public void send(Message msg) {
            msg.sendingUid = Binder.getCallingUid();
            Handler.this.sendMessage(msg);
        }
    }

它是在Handler类中的MessengerImpl方法中获得实现的,这也就能够解释咱们发送的message能够在Handler的handleMessage中出现了。ide

最后咱们再回到Messenger类中看看Messenger的另外一个重要方法:函数

    public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }

这里咱们就能够串联起来了,Messenger类经过传入Handler或是IBinder来得到IMessenger的实例,而后调用send方法实际是在远程调用IMessenger的send方法。this

这里咱们就差很少把Messenger的机制理清了。spa

最后附上刚才实现的例子的一个简图:code

相关文章
相关标签/搜索