跨進程通訊之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

相關文章
相關標籤/搜索