Android-服務Service(Messenger跨進程通訊)

本文學習目標:

  1. 學會如何使用Messenger進行跨進程通訊;
  2. 延伸閱讀:
    Android 消息處理機制:http://www.itdecent.cn/p/02962454adf7

在上一章中介紹了服務使用,服務啟動的兩種方式,startService()和bindService(),startService啟動的服務,跟啟動它的應用組件是沒有聯(lián)系的,因此不管是否跨進程,startService都是可以成功的。而在跨進程服務,bindService()會異常,在onServiceConnected方法中報類型轉(zhuǎn)換異常,說明這時候不能使用這個Binder對象進行轉(zhuǎn)換了。這時候,就需要使用Messenger了。

其實Messenger底層也是使用aidl的方式來實現(xiàn)的,只不過其使用handler來處理消息,因為handler是線程安全的,所以Messenger也是線程安全的,自然Messenger只能處理單線程的問題,如果要使用多線程就該使用aidl的方式實現(xiàn)。

其實,Messenger也是通過bindService的方式,只是需要定義不用的IBinder對象。

主要步驟:

  1. 服務實現(xiàn)Handler,來處理客戶端發(fā)送的消息Message;
  2. 根據(jù)Handler創(chuàng)建一個Messenger對象;
  3. 通過onBinder返回Messenger的Binder對象;
  4. 客戶端使用IBinder將Messenger實例化,然后通過Messenger將Message發(fā)送給服務;

public class MessengerService extends Service {
    public final static String TAG = MessengerService.class.getSimpleName();
    public final static int MSG_SAY_HELLO = 1;

    public MessengerService() {
    }

    @Override
    public void onCreate() {
        Log.d(TAG, "onCreate");
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy");
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * 1. 定義一個Handler,用于處理客戶端發(fā)來的請求
     */
    class ProcessHandler extends Handler{

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MSG_SAY_HELLO:
                    Log.d(TAG, "service receiver from client: say hello");
                    break;

                default:
                        super.handleMessage(msg);
            }

        }
    }

    /**
     * 2. 創(chuàng)建一個Messenger并傳入Handler實例對象
     */
    final Messenger mMessager = new Messenger(new ProcessHandler());

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind");
        // 3.通過onBinder返回Messenger的Binder對象
        return mMessager.getBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(TAG, "onUnbind");
        return super.onUnbind(intent);
    }
}

清單定義:

        <service
            android:name=".MessengerService"
            android:enabled="true"
            android:exported="true"
            android:process=":messengerSer"/>
/**
     * 與服務端交互的Messender
     */
    Messenger mService = null;
    boolean mBound = false;
    /**
     * ServiceConnection代表與服務的連接,
     */
    ServiceConnection cnn2 = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.d("###", "onServiceConnected");
            /**
             * 3. 通過服務端傳遞的IBinder對象,創(chuàng)建相應的Messenger
             * 然后通過Messenger對象與服務端進行交互
             */
            mService = new Messenger(iBinder);
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.d("###", "onServiceDisconnected");
            mService = null;
            mBound = false;
        }
    };
// 綁定服務
Intent intent = new Intent(this, MessengerService.class);
bindService(intent, cnn2, BIND_AUTO_CREATE);
// 解綁服務
unbindService(cnn2);
mBound = false;
// 發(fā)送消息
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO);
try {
    // 4. 通過Messenger發(fā)送消息
    mService.send(msg);
} catch (RemoteException e) {
    e.printStackTrace();
}

流程圖:


流程圖

效果:


image.png

此時,解決了客戶端往服務發(fā)送消息。如果客戶端需要接收服務的消息呢?

我們需要在客戶端定義一個Messenger和Handler,然后發(fā)送消息的時候傳遞這個Messenger。

    /**
     * 定義客戶端的Messenger和Handler
     */
    Messenger repo = new Messenger(new ClientHandler());

    class ClientHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MessengerService.MSG_REPO_SAY_HELLO:
                    Log.d("####", "client receive from server say hello");
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

發(fā)送消息的時候,設(shè)置replyTo

Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO);
msg.replyTo = repo; // 傳遞Messenger
try {
    mService.send(msg);
} catch (RemoteException e) {
    e.printStackTrace();
}

服務在處理Message時候,取出客戶端的Messenger,然后發(fā)送消息

class ProcessHandler extends Handler{

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MSG_SAY_HELLO:
                    Log.d(TAG, "service receiver from client: say hello");
                    Messenger repo = msg.replyTo; // 獲取客戶端Messenger
                    Message rmsg = Message.obtain(null, MSG_REPO_SAY_HELLO);
                    try {
                        // 發(fā)送消息
                        repo.send(rmsg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;

                default:
                        super.handleMessage(msg);
            }

        }
    }

效果:
服務:


服務收到消息

客戶端:


客戶端收到消息
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容