一,寫在前面
在Android中實現IPC機制的方式有多種,例如:AIDL,ContentProvider,Messenger等。AIDL特點是提供AIDL接口的方法,ContentProvider特點是暴露數據庫,Messenger特點是進程間“數據”通信,數據指對象。Messenger實現進程間數據通信是建立在綁定服務基礎上,需要創建一個服務,稱之爲服務端;需要一個客戶端,去綁定服務端。
二,瞭解Messenger構造方法
先來了解Messenger的兩個構造方法:
/**
* Create a new Messenger pointing to the given Handler. Any Message
* objects sent through this Messenger will appear in the Handler as if
* {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had
* been called directly.
*
* @param target The Handler that will receive sent messages.
*/
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
//...
/**
* Create a Messenger from a raw IBinder, which had previously been
* retrieved with {@link #getBinder}.
*
* @param target The IBinder this Messenger should communicate with.
*/
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
Handler.this.sendMessage(msg);
}
}
IMessenger.Stub這個不就是在AIDL中服務端返回的Binder對象麼;參數爲IBinder的構造方法,mTarget不就是AIDL中客戶端中返回的代理對象麼。因此Messenger內部是對AIDL進行了封裝,我們不需要使用AIDL接口,直接調用系統提供給我們的方法就可以了。上面簡單分析了下Messenger內部就是封裝了AIDL技術,下面將介紹如何使用Messenger。
三,服務端實現
首先是服務端,
1,創建一個Service的子類,並重寫了onBinder(intent)方法;
2,創建一個Handler子類實例,並重寫handleMessage(msg)方法;
3,創建一個關聯handler的Messenger對象:Messenger mMessenger = new Messenger(mHandler);mHandler爲第二步中的handler;
4,在onBinder(intent)方法中,調用mMessenger.getBinder()返回binder對象給客戶端;
服務端的代碼:
public class MyService extends Service {
private static final int MSG_FROM_CLIENT = 0;
private static final int MSG_FROM_SERVICE = 1;
private Handler mHandler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_FROM_CLIENT:
//計算值之和
int sum = msg.arg1 + msg.arg2;
//獲取消息中信使
Messenger cs_messenger = msg.replyTo;
//創建新的消息對象
Message m = Message.obtain();
m.what = MSG_FROM_SERVICE;
Bundle b = new Bundle();
b.putInt("sum", sum);
m.obj = b;
//發送消息給client
try {
cs_messenger.send(m);
} catch (Exception e) {
e.printStackTrace();
}
break;
default:
break;
}
};
};
private Messenger mMessenger = new Messenger(mHandler);
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
四,客戶端實現
然後是客戶端:
1,調用bindService方法綁定服務端的Service,在客戶端與Service成功建立連接後,
onServiceConnected方法被回調,可以獲取到Binder對象;
2,創建一個客戶端與服務端通信的信使,Messenger對象,Messenger cs_messenger = new
Messenger(mHandler);mHandler同服務端一樣創建;
3,在onServiceConnected方法中創建Messenger對象,執行:Messenger messenger = new
Messenger(binder);
4,在onServiceConnected方法中創建Message對象,設置Message對象中必要字段what,可選字段
obj,arg1,arg2;以及replyTo(第2步中信使cs_messenger );
5,在onServiceConnected方法中調用:messenger.send(msg)發送消息;
客戶端代碼:
public class MainActivity extends Activity {
private MyServiceConnection conn;
private static final int MSG_FROM_CLIENT = 0;
private static final int MSG_FROM_SERVICE = 1;
private Handler mHandler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_FROM_SERVICE:
//處理service發送的消息
Bundle b = (Bundle) msg.obj;
int sum = b.getInt("sum");
Log.e("MainActivity", "sum:" + sum);
break;
default:
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setAction("com.example.messengerdemo.wang");
conn = new MyServiceConnection();
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
private Messenger cs_messenger = new Messenger(mHandler);
private class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
Log.e("MainActivity", "true");
//創建binder關聯的信使對象
Messenger messenger = new Messenger(service);
//創建一個消息對象
Message msg = Message.obtain(null, MSG_FROM_CLIENT, 10, 20);
msg.replyTo = cs_messenger;//replyTo爲handler關聯的信使
messenger.send(msg);//信使發送消息
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
@Override
protected void onDestroy() {
if (conn != null) {
unbindService(conn);
}
super.onDestroy();
}
}
第1,3步與使用AIDL使用相同,在第3步中創建了構造函數參數爲binder的Messenger對象,實際上就是執行:mTarget = IMessenger.Stub.asInterface(target)。第5步調用了Messenger的send方法發送消息,查看Messenger$send源碼:
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
因此,我們可以得出這樣一個結論:創建一個關聯Binder的Messenger對象,並調用send(msg)方法,其實就是封裝 了AIDL技術,Handler+Message。在客戶端發送消息後,消息是由服務端的handleMessage(msg)處理,這裏完成了一個數據由客戶端-->到服務端的過程。
那麼,服務端獲取了消息中數據,想要給客戶端傳遞數據,那應該怎麼做呢?在服務端中handleMessage()中發送消息給客戶端實現,分這樣幾步:
1,取出Message中的存儲數據的字段obj/arg1/arg2,以及信使replyTo;
2,創建一個新的Message對象,設置字段what,obj/arg1/arg2;
3,使用第1步中的replyTo中存儲信使,調用cs_messenger.send(m),將第2步中消息對象發送給客戶端;
值得一提的是:第三步中發送消息的信使只能是replyTo字段存儲的對象,不能是服務端創建的關聯了handler對象的Messenger。
五,另外
本篇文章提供的服務端的代碼中,在服務端給客戶端傳遞數據時,消息中存儲的數據放在字段obj裏,大家應該注意到Integer數據先經過Bundle對象的封裝,然後才賦值給msg.obj。由於是進程間傳遞數據,對象只能是Parcelable對象,並且賦值給字段obj的對象只能是系統的Parcelable對象,我們自定義的Parcelable對象無法通過obj傳遞。除了字段obj傳遞對象,還可以調用Message$setData(bundle)存放對象。另外,Message,Messenger都實現了Parcelable接口,因此可以進行跨進程的傳輸。
前面服務端向客戶端通過發送消息傳遞了數據,客戶端處理消息是在handleMessage(msg)中,見代碼吧,沒什麼可分析的了,這樣就完成了一個數據由服務端-->到客戶端的過程。上面介紹瞭如何使用Messenger實現數據跨進程傳輸,客戶端-->服務端,然後服務端->客戶端。
這篇文章就分享到這裏啦,有疑問可以留言,亦可糾錯,亦可補充,互相學習...^_^