最近在學(xué)習(xí)Android開(kāi)發(fā)藝術(shù)探索這本書(shū)玖喘,看到Messenger的跨進(jìn)程通信,覺(jué)得書(shū)上講得不錯(cuò)蘑志,所以在這里做個(gè)總結(jié)累奈。
Messenger的思路很簡(jiǎn)單,通過(guò)它可在不同進(jìn)程傳遞Message對(duì)象急但,我們?cè)贛essage中放入我們需要傳遞的數(shù)據(jù)澎媒,就可以輕松實(shí)現(xiàn)數(shù)據(jù)的進(jìn)程間傳遞了。Messenger的底層是AIDL羊始,它對(duì)AIDL做了封裝旱幼,使我們可以更簡(jiǎn)單地進(jìn)行進(jìn)程間通信。
1.服務(wù)端進(jìn)程
public class MessengerService extends Service {
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if (msg.what==MSG){
Toast.makeText(MessengerService.this, msg.getData().getString("msg"), Toast.LENGTH_SHORT).show();
}
}
};
private Messenger messenger = new Messenger(handler);
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return messenger.getBinder();
}
}
看看這個(gè)服務(wù)端代碼突委,我們使用了一個(gè)Handler處理客戶端發(fā)送的Message,從Message取出我們所需的數(shù)據(jù)柏卤。
我們新建了一個(gè)Messenger對(duì)象,從構(gòu)造參數(shù)我們可以看出它和handler相關(guān)聯(lián)匀油。我們?cè)趏nBind()方法中返回了messenger中的binder對(duì)象缘缚。
由于我們處理的是跨進(jìn)程通信,所以別忘了在Manifest文件中給Service加上process屬性.
<service
android:name=".MessengerService"
android:process=":remote"/>
我們知道敌蚜,一個(gè)應(yīng)用的進(jìn)程默認(rèn)名稱(chēng)為包名桥滨,應(yīng)用內(nèi)的所有組件都運(yùn)行在這個(gè)進(jìn)程內(nèi),如果想讓某個(gè)組件獨(dú)立運(yùn)行在另一個(gè)進(jìn)程,那么則加上process屬性齐媒,這里的“:remote”全程應(yīng)該是包名:remote,省去了前面的包名蒲每。
2.客戶端進(jìn)程##
public class MainActivity extends AppCompatActivity {
private Messenger messenger;
public static final int MSG = 1;
private Button btn;
private ServiceConnection connection = new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
messenger = new Messenger(service);
Message message = Message.obtain(null,MSG);
Bundle bundle = new Bundle();
bundle.putString("msg","helloworld");
message.setData(bundle);
try {
messenger.send(message);
} 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);
btn = (Button) findViewById(R.id.bindService);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,MessengerService.class); bindService(intent,connection,BIND_AUTO_CREATE);
}
});
}
@Override
protected void onDestroy() {
unbindService(connection);
super.onDestroy();
}
}
這個(gè)代碼我們也比較熟悉了,跟平常bindService在客戶端和服務(wù)端在同一進(jìn)程的寫(xiě)法相似喻括。區(qū)別在于使用了Messenger.
同樣地我們?cè)诳蛻舳艘惨陆ㄒ粋€(gè)Messenger對(duì)象邀杏,在構(gòu)造參數(shù)里傳入返回的binder對(duì)象。
我們?cè)贛essage中放入我們要的數(shù)據(jù)唬血,借助的是Bundle望蜡,最后用messenger.send(message);發(fā)送過(guò)去即可。
我們運(yùn)行一下程序拷恨,可見(jiàn)服務(wù)端收到了Messenger發(fā)來(lái)的信息脖律。
在Messenger傳輸數(shù)據(jù)需要將數(shù)據(jù)放入Message.我們都知道,跨進(jìn)程運(yùn)輸?shù)臄?shù)據(jù)需要實(shí)現(xiàn)序列化腕侄,所以Messenger和Message必定實(shí)現(xiàn)了Parcelable接口小泉,看下源碼
public final class Message implements Parcelable
public final class Messenger implements Parcelable
Message的載體有what,arg1,arg2,Bundle,object和replyTo,在同一進(jìn)程內(nèi),obj很常用兜挨,但是在跨進(jìn)程中就不行了膏孟,只有系統(tǒng)提供的Parcelable對(duì)象才可以通過(guò)它進(jìn)行傳輸,我們自己定義的Parcelable對(duì)象是無(wú)法通過(guò)它傳輸?shù)陌杌恪5俏覀冞€有Bundle,只要對(duì)象實(shí)現(xiàn)了Parcelable接口弊决,利用bundle.putExtra(key,object)就能傳遞數(shù)據(jù)了噪舀,這里我們只演示傳遞String類(lèi)型數(shù)據(jù)。
接下來(lái)我們?cè)賮?lái)看看服務(wù)端如何回復(fù)客戶端發(fā)送的消息飘诗。
當(dāng)服務(wù)端接收到客戶端的消息時(shí)与倡,我們也新建一個(gè)Messenger對(duì)象回復(fù)客戶端,代碼如下
//重點(diǎn)在這句話
Messenger messenger = msg.replyTo;
Message replyMessage = Message.obtain(null,REPLYMESSAGE);
Bundle bundle = new Bundle();
bundle.putString("reply","好的我知道了");
replyMessage.setData(bundle);
messenger對(duì)象由replyTo賦值昆稿。而replyTo來(lái)自客戶端的Messenger,這樣兩者就建立聯(lián)系纺座。
再看看客戶端的修改,我們新建了Handler對(duì)象和Mssenger對(duì)象溉潭。
private Handler getReplyHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what==REPLYMESSAGE){
Toast.makeText(MainActivity.this,msg.getData().getString("reply"),Toast.LENGTH_SHORT).show();
}
}
};
private Messenger getReplyMessenger = new Messenger(getReplyHandler);
然后我們需要把接收服務(wù)端回復(fù)的Messenger通過(guò)Message的replyTo參數(shù)傳遞給服務(wù)端净响,這句話有點(diǎn)難理解,多看幾遍喳瓣。
private ServiceConnection connection = new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
messenger = new Messenger(service);
Message message = Message.obtain(null,MSG);
Bundle bundle = new Bundle();
bundle.putString("msg","成功進(jìn)行跨進(jìn)程通信馋贤!");
message.setData(bundle);
//這句話與服務(wù)端的Messenger messenger = msg.replyTo;相對(duì)應(yīng),缺一不可
message.replyTo = getReplyMessenger;
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
再運(yùn)行一下程序
最后再放上一張Messenger的工作原理畏陕,找不到書(shū)上的原圖配乓,只能自己畫(huà)了。