使用Messenger進(jìn)行跨進(jìn)程通信

最近在學(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)的信息脖律。

776440378629156779.png

在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)行一下程序

230912919011775556.png

最后再放上一張Messenger的工作原理畏陕,找不到書(shū)上的原圖配乓,只能自己畫(huà)了。


Messenger.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市犹芹,隨后出現(xiàn)的幾起案子崎页,更是在濱河造成了極大的恐慌,老刑警劉巖腰埂,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件实昨,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡盐固,警方通過(guò)查閱死者的電腦和手機(jī)荒给,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)刁卜,“玉大人志电,你說(shuō)我怎么就攤上這事』着浚” “怎么了挑辆?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)孝情。 經(jīng)常有香客問(wèn)我鱼蝉,道長(zhǎng),這世上最難降的妖魔是什么箫荡? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任魁亦,我火速辦了婚禮,結(jié)果婚禮上羔挡,老公的妹妹穿的比我還像新娘洁奈。我一直安慰自己,他們只是感情好绞灼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布利术。 她就那樣靜靜地躺著,像睡著了一般低矮。 火紅的嫁衣襯著肌膚如雪印叁。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,190評(píng)論 1 299
  • 那天军掂,我揣著相機(jī)與錄音轮蜕,去河邊找鬼。 笑死良姆,一個(gè)胖子當(dāng)著我的面吹牛肠虽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播玛追,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼税课,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼官还!你這毒婦竟也來(lái)了琐鲁?” 一聲冷哼從身側(cè)響起晃洒,我...
    開(kāi)封第一講書(shū)人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤损谦,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后找颓,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體合愈,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年击狮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了佛析。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡彪蓬,死狀恐怖寸莫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情档冬,我是刑警寧澤膘茎,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站酷誓,受9級(jí)特大地震影響披坏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜盐数,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一棒拂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧娘扩,春花似錦着茸、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)猜绣。三九已至灰殴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掰邢,已是汗流浹背牺陶。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辣之,地道東北人掰伸。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像怀估,于是被迫代替她去往敵國(guó)和親狮鸭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子合搅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容