IPC方式(Bundle、文件共享、Messenger)--《Android開發藝術探索》閱讀筆記——第二章part2

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/hfy8971613/article/details/80206958

一、使用Bundle

在一個進程中使用另外一個進程的Activity,Service,Receiver,在Bunlder中附加我們需要傳輸給遠程進程的信息,然後用intent發送過去,當然,我們傳輸的數據必須能夠序列化,比如基本數據類型,實現了Parcelable接口的對象,實現了Serializable接口的對象以及一些Android支持的特殊對象(具體內容可以看下Bundler這個類,Bundler不支持的類型我們無法通過他在進程間傳遞數據)——這是一種很簡單的進程間通信方式。

二、使用文件共享

1、文件共享是一種不錯的進程間通訊的方式,兩個進程通過讀/寫同一個文件來交換數據,比如A進程把數據寫入文件,B再去讀取。
2、通過文件共享的方式也是有侷限性的,如果併發讀/寫,那麼我們讀出的內容就有可能不是最新的,如果是併發寫的話那就更嚴重了。

3、SharedPreferences也屬於文件的一種,但是由於系統對它的讀/寫有一定的緩存策略,即在內存中會有一份SharedPreferences文件的緩存,因此在多進程模式下,系統對它的讀/寫就變得不可靠,當面對高併發的讀/寫訪問Sharedpreferences有很大機率會丟失數據,因此,不建議在進程間通信中使SharedPreferences。

三、使用Messenger

在不同進程中傳遞Message對象,在Message中放入我們需要傳遞的數據,就可以輕鬆地實現數據的進程間傳遞了。Messenger是一種輕量級的IPC方案,它的底層實現是AIDL。

  • 服務端進程
首先,我們需要在服務端創建一個Service來處理客戶端的連接請求,同時創建一個Handler並通過它來創建一個Messenger對象,然後在Service的onBind中返回這個Messenger對象底層的Binder即可。
  • 客戶端進程

客戶端進程中,首先要綁定服務端的Service,綁定成功後用服務端返回的IBinder對象創建一個Messenger,通過這個Messenger就可以向服務端發送消息了,發消息類型爲 Message對象。

如果需要服務端能夠迴應客戶端,就和服務端一樣,我們還需要創建一個Handdler並創建一個新的Messenger,並把這個Messenger對象通過Message的replyTo參數傳遞給服務端,服務端通過這個replyTo參數就可以迴應客戶端。

1、看一個簡單點的例子,這個例子中服務端無法迴應客戶端。

服務端:這是服務端的典型代碼,可以看到MessengerHandler用來處理客戶端發送的消息,並從消息中取出客戶端發來的文本信息,而mMessenger是一個Messenger對象,他和MessengerHandler相關聯,並在onBind方法中返回他裏面的IBind對象

public class MessengerService extends Service {

    public static final String TAG = "MessengerService";

    private static class MessengerHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 100:
                    Log.i(TAG,"數據:" + msg.getData());
                    break;
                default:
                super.handleMessage(msg);
            }
        }
    }

    private final Messenger mMessenger = new Messenger(new MessengerHandler());

    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }
}

客戶端如下:

public class MessengerActivity extends AppCompatActivity {

    public static final String TAG = "MessengerActivity";

    private Messenger mService;

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mService =  new Messenger(service);
            Message msg = Message.obtain(null,10);
            Bundle data = new Bundle();
            data.putString("msg","hell this is client");
            msg.setData(data);
            try {
                mService.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

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

        Intent intent = new Intent(this,MessengerService.class);
        bindService(intent,mConnection, Context.BIND_AUTO_CREATE);
    }

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

這樣運行之後就能收到發送的消息了。

通過上面的例子可以看出,在Messenger中進行數據傳遞必須將數據放入Messsage中,而Messenger和Message都實現了Parcelable接口,因此可以跨進程傳輸,簡單來說,Messebger所支持的數據類型就是Message所支持的傳輸類型。實際上,通過 Messenger來傳遞Message,Message中能使用的載體就只有what、arg1、arg2、Bundle以及replyTo。Message的另一個字段object在同一個進程中是很實用的,但是在進程間通信的時候,在Android2.2以前object字段不支持跨進程傳輸,即便是2.2以後,也僅僅是系統提供的實現了Parcelable接口的對象才能通過它來傳輸。這就意味着我們自定義的Parcelable對象是無法通過object字段來傳輸的,讀者可以試一下。非系統的Parcelable對象的確無法通過object字段來傳輸,這也導致了object字段的實用性大大降低,所幸我們還有Bundle,Bundle中 可以支持大量的數據類型。

2、有時候我們還需要能迴應客戶端,下面就介紹下:

還是採用上面的例子,但是稍微做一下修改,每當客戶端發來一條消息,服務端就會自動回覆一條“嗯,你的消息我已經收到,稍後 回覆你。”,這很類似郵箱的自動回覆功能。

首先看服務端的修改,服務端只需要修改MessengerHandler,當收到消息後,會立即回覆一條消息給客戶端

private static class MessengerHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 100:
                    Log.i(TAG,"數據:" + msg.getData());
                    Messenger messenger = msg.replyTo;
                    Message reply = Message.obtain(null,200);
                    Bundle bundle = new Bundle();
                    bundle.putString("reply","收到你的消息,等下回復");
                    try {
                        messenger.send(reply);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

接着來看客戶端的修改,爲了接受服務端的恢復,客戶端也需要準備一個接收消息的Messenger和handler,如下:

private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler());

    private static class MessengerHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 200:
                    Log.i(TAG,"Service:" + msg.getData().getString("reply"));
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

除了上述的修改,還有關鍵的一點,當客戶端發送消息的時候,需要把接收服務端回覆的Messenger通過Message的replyTo參數傳遞給服務端,如下:

private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mService =  new android.os.Messenger(service);
            Message msg = Message.obtain(null,100);
            Bundle data = new Bundle();
            data.putString("msg","hell this is client");
            //注意這句話
            msg.replyTo  = mGetReplyMessenger;
            msg.setData(data);
            try {
                mService.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };
通過上述的修改,我們再次運行,就達到了自動回覆的效果了;
到這裏,我們採用Messenger進程通訊的例子就說完了,我們畫一張工作原理圖,這樣更加便於理解:




另外,




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章