Messenger實現多程序通訊
阿新 • • 發佈:2019-02-14
Messenger進行多程序通訊時一次處理一個請求,在服務端不用考慮執行緒同步的問題,因為服務端不存在併發執行的情況。它的作用主要是為了傳遞訊息,如果需要跨程序呼叫服務端的方法就不適合使用。
用Messenger實現多執行緒通訊時,服務端:
在服務端建立一個Service來處理客戶端的連線請求,同時建立一個Handler並通過這個Handler來建立一個Messenger物件,然後在Service的onBaind方法中返回這個Messenger物件底層的Binder即可。程式碼如下:
public class MessengerService extends Service { private static final intService在Android Manifest檔案中的註冊為:SAY_HOLLE = 0;private static final String TAG = "MessengerService"; private static class MessengerHandler extends Handler{ @Override public void handleMessage(Message msg) { switch(msg.what){ case SAY_HOLLE: Log.e(TAG, "receive msg from client:" + msg.getData().getString("msg"));break; default: super.handleMessage(msg); } } } private final Messenger mMessenger = new Messenger(new MessengerHandler()); @Nullable @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); } }
<通過Android Manifest檔案中給Service指定process屬性來實現與客戶端處於不同的程序。service android:name=".MessengerService" android:exported="true" android:enabled="true" android:process=":remote"/>
客戶端:
客戶端程序首先要繫結服務端的Service,繫結成功之後用服務端返回的IBinder物件建立一個Messenger,即通過onServiceConnected()方法中的IBinder service引數建立一個客戶端的Messenger物件,然後通過這個Messenger就可以向服務端傳送訊息了,傳送的訊息是Message型別。(新建Message物件,Bundle物件,Bundle物件中放入需要往服務端傳送的訊息內容,然後將Bundle物件放進Message物件中,最後通過Messenger物件將該Message傳送給服務端)程式碼如下圖所示:
public class MainActivity extends AppCompatActivity { private static final int SAY_HOLLE = 0;private static final String TAG = "MainActivity"; 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, SAY_HOLLE,0,0); Bundle data = new Bundle(); data.putString("msg", "hello, 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_main); Log.e(TAG, "onCreate"); Intent intent = new Intent(this, MessengerService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { unbindService(mConnection); super.onDestroy(); Log.e(TAG, "onDestroy"); } }這樣就完成了利用Messenger實現程序間通訊的功能。如果需要實現服務端能夠迴應客戶端,那麼客戶端就應該和服務端一樣,需要新建一個Handler,並通過這個Handler新建一個新的Messenger,將這個Messenger物件通過Message的replyTo引數傳遞給服務端,服務端通過這個replyTo引數在服務端新建一個Messenger物件,傳送Message型別的引數就可以迴應客戶端。
實現上述功能客戶端需要新增的程式碼是:
private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler()); private static class MessengerHandler extends Handler{ @Override public void handleMessage(Message msg) { switch(msg.what){ case TO_HOLLE: Log.e(TAG, "receiver msg from Service:" + msg.getData().getString("reply")); break; default: super.handleMessage(msg); } } }和
msg.replyTo = mGetReplyMessenger;
服務端需要新增的程式碼是:
Messenger client = msg.replyTo; Message replyMessage = Message.obtain(null, TO_HOLLE); Bundle bundle = new Bundle(); bundle.putString("reply", "嗯, 你的訊息我已經收到, 稍後會回覆你"); replyMessage.setData(bundle); try { client.send(replyMessage); } catch (RemoteException e) { e.printStackTrace(); }服務端總的完整程式碼就是:
/** * Created by su on 2017/10/26. */ public class MessengerService extends Service { private static final int SAY_HOLLE = 0; private static final int TO_HOLLE = 1; private static final String TAG = "MessengerService"; private static class MessengerHandler extends Handler{ @Override public void handleMessage(Message msg) { switch(msg.what){ case SAY_HOLLE: Log.e(TAG, "receive msg from client:" + msg.getData().getString("msg")); Messenger client = msg.replyTo; Message replyMessage = Message.obtain(null, TO_HOLLE); Bundle bundle = new Bundle(); bundle.putString("reply", "嗯, 你的訊息我已經收到, 稍後會回覆你"); replyMessage.setData(bundle); try { client.send(replyMessage); } catch (RemoteException e) { e.printStackTrace(); } break; default: super.handleMessage(msg); } } } private final Messenger mMessenger = new Messenger(new MessengerHandler()); @Nullable @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); } }客戶端程式碼是:
public class MainActivity extends AppCompatActivity { private static final int SAY_HOLLE = 0; private static final int TO_HOLLE = 1; private static final String TAG = "MainActivity"; private Messenger mService; private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler()); private static class MessengerHandler extends Handler{ @Override public void handleMessage(Message msg) { switch(msg.what){ case TO_HOLLE: Log.e(TAG, "receiver msg from Service:" + msg.getData().getString("reply")); break; default: super.handleMessage(msg); } } } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mService = new Messenger(service); Message msg = Message.obtain(null, SAY_HOLLE,0,0); Bundle data = new Bundle(); data.putString("msg", "hello, this is client."); msg.setData(data); // msg.replyTo = mGetReplyMessenger; 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_main); Log.e(TAG, "onCreate"); Intent intent = new Intent(this, MessengerService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { unbindService(mConnection); super.onDestroy(); Log.e(TAG, "onDestroy"); } }最後在logcat觀察列印輸出的結果時,由於服務端和客戶端在一個應用的不同程序,客戶端在預設的包名程序下,這樣不加設定的話只能看到客戶端的log列印輸出結果,如果要檢視服務端的log列印結果,應該在log上設定過濾器,這樣才能檢視服務端的日誌列印結果。如:
這樣在logcat中觀察服務端列印的資訊就如下圖所示: