Android處理序間通訊之使用Messenger,androidmessenger
Messenger,信使,可使用它進行進程間的通訊,而Messenger對Service的請求採用隊列的方式,因此它不支援多線程通訊。
看看官方文檔對於Messenger的解釋:
Reference to a Handler, which others can use to send messages to it. This allows for the implementation of
message-based communication across processes, by creating a Messenger pointing to a Handler in one process,
and handing that Messenger to another process.
用戶端和服務端可相互持有對方的Messenger來進行通訊,下面我們來看看具體的實現。
在eclipse下建立兩個工程,分別為用戶端和服務端:
用戶端的實現,建立用戶端的Messenger,使用Messenger的構造方法指向一個handler執行個體,此handler用於處理服務端發過來的訊息。
而用戶端通過onServiceConnected獲得服務端的Messenger,使用此Messenger給服務端發送訊息,用戶端的Messenger通過Message的replyTo傳遞給服務端。
1 public class MainActivity extends Activity { 2 3 private static final String TAG = "--DEBUG--"; 4 5 // 用於啟動service的ACTION 6 private static final String START_SERVER_ACTION = "com.young.server.START_SERVICE"; 7 private static final int WHAT_ON_TO_SERVICE = 1; 8 private static final int WHAT_ON_TO_CLIENT = 2; 9 10 private Button mBindBtn;11 private boolean isBindService = false;12 13 @Override14 protected void onCreate(Bundle savedInstanceState) {15 super.onCreate(savedInstanceState);16 setContentView(R.layout.activity_main);17 mBindBtn = (Button) findViewById(R.id.bind_service);18 mBindBtn.setOnClickListener(new OnClickListener() {19 @Override20 public void onClick(View v) {21 bindService(new Intent(START_SERVER_ACTION), conn, Context.BIND_AUTO_CREATE);22 }23 });24 }25 26 // client端Handler,用於處理server端發來的訊息27 private Handler mClientHandler = new Handler(new Callback() {28 @Override29 public boolean handleMessage(Message msg) {30 switch (msg.what) {31 case WHAT_ON_TO_CLIENT:32 Log.v(TAG, "用戶端收到服務端發來的訊息!");33 break;34 35 default:36 break;37 }38 return false;39 }40 });41 42 // client端Messenger43 private Messenger mClientMessenger = new Messenger(mClientHandler);44 45 private ServiceConnection conn = new ServiceConnection() {46 47 @Override48 public void onServiceDisconnected(ComponentName name) {49 Log.v(TAG, "服務已斷開");50 51 isBindService = false;52 mClientMessenger = null;53 }54 55 @Override56 public void onServiceConnected(ComponentName name, IBinder service) {57 Log.v(TAG, "服務已連結");58 59 isBindService = true;60 // 獲得server端信使Messenger執行個體61 Messenger serverMessenger = new Messenger(service);62 // 向server端發送的訊息63 Message toServerMessage = Message.obtain(null, WHAT_ON_TO_SERVICE);64 // 通過replyTo把client端的信使傳遞給service65 toServerMessage.replyTo = mClientMessenger;66 try {67 serverMessenger.send(toServerMessage);68 } catch (RemoteException e) {69 e.printStackTrace();70 }71 }72 };73 74 protected void onStop() {75 if (isBindService)76 unbindService(conn);77 super.onStop();78 };79 }
服務端Service的實現,服務端接收到用戶端的訊息以後,通過Message的replyTo取出用戶端的Messenger,使用此Messenger給用戶端發送訊息,這就實現了進程之間的雙向通訊。
服務端通過Messenger的getBinder方法將IBinder對象返給用戶端,用於共用服務端的Messenger。
1 public class RemoteService extends Service { 2 private static final String TAG = "--DEBUG--"; 3 4 private static final int WHAT_ON_TO_SERVICE = 1; 5 private static final int WHAT_ON_TO_CLIENT = 2; 6 7 // server端handler,用來處理client發來的訊息 8 private Handler mServerHandler = new Handler(new Callback() { 9 @Override10 public boolean handleMessage(Message msg) {11 switch (msg.what) {12 case WHAT_ON_TO_SERVICE:13 Log.v(TAG, "收到用戶端發來的訊息");14 // server端獲得client端的信使Messenger15 Messenger clientMessenger = msg.replyTo;16 Message toClientMsg = Message.obtain(null, WHAT_ON_TO_CLIENT);17 try {18 // 使用用戶端Messenger向用戶端發送訊息19 clientMessenger.send(toClientMsg);20 } catch (RemoteException e) {21 e.printStackTrace();22 }23 break;24 25 default:26 break;27 }28 return false;29 }30 });31 32 // server端信使Messenger33 private Messenger mServerMessenger = new Messenger(mServerHandler);34 35 @Override36 public IBinder onBind(Intent intent) {37 return mServerMessenger.getBinder();38 }
再來看看服務端service的聲明,因為要在其他進程中啟動service,所以設定android:exported為true,此外還為service加入啟動了許可權。
1 <permission android:protectionLevel="normal" android:name="young.permission.START_SERVICE"></permission> 2 3 <service 4 android:name="com.young.server.RemoteService" 5 android:permission="young.permission.START_SERVICE" 6 android:exported="true" > 7 <intent-filter> 8 <action android:name="com.young.server.START_SERVICE" /> 9 </intent-filter>10 </service>
最後要在用戶端添加相應的啟動Service許可權。
<uses-permission android:name="young.permission.START_SERVICE" />
程式運行後的結果,可以看到用戶端和服務端都收到了對方發來的訊息。
11-12 12:58:37.197: V/--DEBUG--(21322): 服務已連結
11-12 12:58:37.197: V/--DEBUG--(21268): 收到用戶端發來的訊息
11-12 12:58:37.197: V/--DEBUG--(21322): 用戶端收到服務端發來的訊息!