Android 多程式之Messenger的使用

xxq2dream發表於2018-08-27

Android多程式系列

Messenger也可以作為Android多程式的一種通訊方式,通過構建Message來在客戶端和服務端之間傳遞資料

簡單使用Messenger

客戶端通過Messenger向服務端程式傳送訊息
  • 構建一個執行在獨立程式中的服務端Service:
public class MessengerService extends Service {
    private static final String TAG = "MessagerService";

    /**
     * 處理來自客戶端的訊息,並用於構建Messenger
     */
    private static class MessengerHandler extends Handler {
        @Override
        public void handleMessage(Message message) {
            switch (message.what) {
                case MESSAGE_FROM_CLIENT:
                    Log.e(TAG, "receive message from client:" + message.getData().getString("msg"));
                    break;
                default:
                    super.handleMessage(message);
                    break;
            }
        }
    }

    /**
     * 構建Messenger物件
     */
    private final Messenger mMessenger = new Messenger(new MessengerHandler());

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        //將Messenger物件的Binder返回給客戶端
        return mMessenger.getBinder();
    }
}
複製程式碼
  • 註冊service,當然要設定在不同的程式
<service
    android:name="com.xxq2dream.service.MessengerService"
    android:process=":remote" />
複製程式碼
  • 然後客戶端是通過繫結服務端返回的binder來建立Messenger物件,並通過這個Messenger物件來向服務端傳送訊息
public class MessengerActivity extends AppCompatActivity {
    private static final String TAG = "MessengerActivity";

    private Messenger mService;

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.e(TAG, "ServiceConnection-->" + System.currentTimeMillis());
            //通過服務端返回的Binder建立Messenger
            mService = new Messenger(iBinder);
            //建立訊息,通過Bundle傳遞資料
            Message message = Message.obtain(null, MESSAGE_FROM_CLIENT);
            Bundle bundle = new Bundle();
            bundle.putString("msg", "hello service,this is client");
            message.setData(bundle);
            try {
                //向服務端傳送訊息
                mService.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.e(TAG, "onServiceDisconnected-->binder died");
        }
    };

    @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() {
        //解綁服務
        unbindService(mConnection);
        super.onDestroy();
    }
}
複製程式碼

服務端接收到客戶端的訊息

通過上面的實踐,我們可以看出利用Messenger進行跨程式通訊,需要通過Message來傳遞訊息,而Message可以通過setData方法利用Bundle來傳遞複雜的資料。
服務端如果要回復訊息給客戶端,那就要用到Message的replyTo引數了
  • 服務端改造
private static class MessengerHandler extends Handler {
    @Override
    public void handleMessage(Message message) {
        switch (message.what) {
            case Constant.MESSAGE_FROM_CLIENT:
                Log.e(TAG, "receive message from client:" + message.getData().getString("msg"));
                //獲取客戶端傳遞過來的Messenger,通過這個Messenger回傳訊息給客戶端
                Messenger client = message.replyTo;
                //當然,回傳訊息還是要通過message
                Message msg = Message.obtain(null, Constant.MESSAGE_FROM_SERVICE);
                Bundle bundle = new Bundle();
                bundle.putString("msg", "hello client, I have received your message!");
                msg.setData(bundle);
                try {
                    client.send(msg);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
            default:
                super.handleMessage(message);
                break;
        }
    }
}
複製程式碼
  • 客戶端改造,主要是通過Handle構建一個Messenger物件,並在向服務端傳送訊息的時候,通過Message的replyTo引數將Messenger物件傳遞給服務端
/**
 * 用於構建客戶端的Messenger物件,並處理服務端的訊息
 */
private static class MessengerHandler extends Handler {
    @Override
    public void handleMessage(Message message) {
        switch (message.what) {
            case Constant.MESSAGE_FROM_SERVICE:
                Log.e(TAG, "receive message from service:" + message.getData().getString("msg"));
                break;
            default:
                super.handleMessage(message);
                break;
        }
    }
}

/**
 * 客戶端Messenger物件
 */
private Messenger mClientMessenger = new Messenger(new MessengerHandler());

private ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        Log.e(TAG, "ServiceConnection-->" + System.currentTimeMillis());
        mService = new Messenger(iBinder);
        Message message = Message.obtain(null, MESSAGE_FROM_CLIENT);
        Bundle bundle = new Bundle();
        bundle.putString("msg", "hello service,this is client");
        message.setData(bundle);
        //將客戶端的Messenger物件傳遞給服務端
        message.replyTo = mClientMessenger;
        try {
            mService.send(message);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        Log.e(TAG, "onServiceDisconnected-->binder died");
    }
};
複製程式碼

客戶端收到服務端的訊息回覆

總結
  • 使用Messager來傳遞Message,Message中能使用的欄位只有what、arg1、arg2、Bundle和replyTo,自定義的Parcelable物件無法通過object欄位來傳輸
  • Message中的Bundle支援多種資料型別,replyTo欄位用於傳輸Messager物件,以便程式間相互通訊
  • Messager以序列的方式處理客戶端發來的訊息,不適合有大量併發的請求
  • Messager方法只能傳遞訊息,不能跨程式呼叫方法

                     歡迎關注我的微信公眾號,期待與你一起學習,一起交流,一起成長!
複製程式碼

AntDream

相關文章