Activity和Service的跨進(jìn)程雙向通信機(jī)制

對(duì)于不同進(jìn)程中的Activity和Service侧巨,要實(shí)現(xiàn)IPC(跨進(jìn)程通信)愧捕,其實(shí)就是通過(guò)IBinder接口,其中可能涉及到AIDL編程兔综,和操作系統(tǒng)提供的進(jìn)程通信接口這些底層c++知識(shí)燕刻。然而只泼,Google已經(jīng)為我們封裝了一套Messenger機(jī)制,其底層也是使用AIDL實(shí)現(xiàn)的卵洗。要使用這套機(jī)制请唱,必須為通信雙方建立各自的Messenger,然后Service的Messenger依然是通過(guò)IBinder傳遞到Activity忌怎,Activity也可以將自己的Messenger通過(guò)Message的replyTo屬性傳遞到Service籍滴。

Messenger使用步驟:

  1. Service需要實(shí)現(xiàn)一個(gè)Hanlder,用以處理從客戶端收到的消息
  2. 用該Handler創(chuàng)建一個(gè)Messenger對(duì)象榴啸,Messenger對(duì)象內(nèi)部會(huì)引用該Handler對(duì)象
  3. 用創(chuàng)建好的Messenger對(duì)象獲得一個(gè)IBinder實(shí)例孽惰,并且將該IBinder通過(guò)Service的onBind方法返回給各個(gè)客戶端
  4. 客戶端通過(guò)收到的IBinder對(duì)象實(shí)例化一個(gè)Messenger對(duì)象,該Messenger內(nèi)部指向指向Service中的Handler鸥印⊙Γ客戶端通過(guò)該Messenger對(duì)象就可以向Service中的Hanlder發(fā)送消息坦报。
  5. Service中的Hanlder收到消息后,在Handler中的handleMessage方法中處理消息狂鞋。
  6. 通過(guò)上面的第4步與第5步片择,就完成了客戶端向Service發(fā)送消息并且Service接收到消息的單向通信過(guò)程,即客戶端 -> Service骚揍。如果要實(shí)現(xiàn)Service向客戶端回消息的通信過(guò)程字管,即Service -> 客戶端,那么前提是在客戶端中也需要像Service一樣內(nèi)部維護(hù)有一個(gè)指向Handler的Messenger信不。當(dāng)在第四步中客戶端向Service發(fā)送信息時(shí)嘲叔,將Message的replyTo屬性設(shè)置為客戶端自己的Messenger。這樣在第5步Service在Handler的handleMessage中處理收到的消息時(shí)抽活,可以通過(guò)Message的Messenger再向客戶端發(fā)送Message硫戈,這樣客戶端內(nèi)維護(hù)的Handler對(duì)象就會(huì)收到來(lái)自于Service的Message,從而完成Service向客戶端發(fā)送消息且客戶端接收到消息的通信過(guò)程下硕。
    綜上六步就能完成客戶端與Service的跨進(jìn)程雙向通信過(guò)程:
    客戶端 -> Service -> 客戶端

為了演示客戶端與Service的跨進(jìn)程通信丁逝,我建立了兩個(gè)應(yīng)用ClientApp和ServiceApp,兩個(gè)應(yīng)用的名稱(chēng)也是見(jiàn)名知意:

  1. ClientApp, 該App是客戶端梭姓,用于調(diào)用服務(wù)
  2. ServiceApp霜幼,該App是Service端,用于供客戶端ClientApp調(diào)用
    注意:跨進(jìn)程通信使用Bundle糊昙,否則會(huì)報(bào)錯(cuò)Java.lang.RuntimeException: Can’t marshal non-Parcelable objects across processes.

客戶端demo

package com.axaet.servicecommunication;

import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {

private static final String TAG = "yushu";


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    textView = (TextView) findViewById(R.id.text_show);
    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    assert fab != null;
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Message message = Message.obtain(null, 101);
            bundle.putString("key","from MainActivity button");
            message.setData(bundle);
            message.replyTo = messenger;
            try {
                mService.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    });
}

String getCurProcessName(Context context) {
    int pid = android.os.Process.myPid();
    ActivityManager mActivityManager = (ActivityManager) context
            .getSystemService(Context.ACTIVITY_SERVICE);
    for (ActivityManager.RunningAppProcessInfo appProcess : mActivityManager
            .getRunningAppProcesses()) {
        if (appProcess.pid == pid) {
            return appProcess.processName;
        }
    }
    return null;
}

class MyHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
            case 111:
                int i = msg.arg1;
                if (i == 1) {
                    Log.i(TAG,"Main="+getCurProcessName(getApplication()));
                    Bundle bundle=msg.getData();
          Toast.makeText(MainActivity.this, "接收到Service消息"+bundle.getString("key"), Toast.LENGTH_SHORT).show();
                }
            default:
        }
    }
}

private Bundle bundle = new Bundle();
private Messenger messenger = new Messenger(new MyHandler());
private Messenger mService;
private TextView textView;
private ServiceConnection serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.i(TAG, "onServiceConnected: ComponentName = " + name);
        mService = new Messenger(service);
        textView.setText("連接成功");
        Message message = Message.obtain(null, 101);
        bundle.putString("key","from MainActivity=11111");
        message.setData(bundle);
        message.replyTo = messenger;
        try {
            mService.send(message);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
    }
};


@Override
protected void onStart() {
    super.onStart();
    Intent intent = new Intent();
    //參數(shù)一為服務(wù)端APP包名辛掠,參數(shù)二為service的完整類(lèi)名
    ComponentName name = new ComponentName("com.axaet.servicecommunication", "com.axaet.servicecommunication.MyService");
    intent.setComponent(name); //發(fā)送信息
    intent.putExtra("data", "msg from MainActivity");
    bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}

@Override
protected void onStop() {
    super.onStop();
    unbindService(serviceConnection);
}
}

服務(wù)端demo

package com.axaet.servicecommunication;

import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

public class MyService extends Service {
private static final String TAG = "yushu";
public List<String> data = new ArrayList<>();
private Messenger mClient;

@SuppressLint("HandlerLeak")
class MyHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
            case 101:
                Bundle bundle=msg.getData();
                Log.i(TAG,"service="+ bundle.getString("key"));
                Log.i(TAG,"service="+getCurProcessName(getApplication()));
                Message message = Message.obtain(null, 111, 1, 1);
                bundle.putString("key","from service222222");
                message.setData(bundle);
                mClient = msg.replyTo;
                try {
                    mClient.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            default:
        }
    }
}

String getCurProcessName(Context context) {
    int pid = android.os.Process.myPid();
    ActivityManager mActivityManager = (ActivityManager) context
            .getSystemService(Context.ACTIVITY_SERVICE);
    for (ActivityManager.RunningAppProcessInfo appProcess : mActivityManager
            .getRunningAppProcesses()) {
        if (appProcess.pid == pid) {

            return appProcess.processName;
        }
    }
    return null;
}

private Messenger messenger = new Messenger(new MyHandler());

public MyService() {
    data.add("This is some msg from " + TAG);
}

@Override
public IBinder onBind(Intent intent) {
    String s = intent.getStringExtra("data");
    Log.i(TAG, "onBind: 接收 " + s);
    data.add(s);
    return messenger.getBinder();
}
}

參考文章:http://blog.csdn.net/zhou114108/article/details/52050242

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谢谦,一起剝皮案震驚了整個(gè)濱河市释牺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌回挽,老刑警劉巖没咙,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異千劈,居然都是意外死亡祭刚,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)墙牌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)涡驮,“玉大人,你說(shuō)我怎么就攤上這事喜滨∽酵保” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵虽风,是天一觀的道長(zhǎng)棒口。 經(jīng)常有香客問(wèn)我寄月,道長(zhǎng),這世上最難降的妖魔是什么无牵? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任漾肮,我火速辦了婚禮,結(jié)果婚禮上茎毁,老公的妹妹穿的比我還像新娘克懊。我一直安慰自己,他們只是感情好七蜘,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布保檐。 她就那樣靜靜地躺著,像睡著了一般崔梗。 火紅的嫁衣襯著肌膚如雪夜只。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,079評(píng)論 1 285
  • 那天蒜魄,我揣著相機(jī)與錄音扔亥,去河邊找鬼。 笑死谈为,一個(gè)胖子當(dāng)著我的面吹牛旅挤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播伞鲫,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼粘茄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了秕脓?” 一聲冷哼從身側(cè)響起柒瓣,我...
    開(kāi)封第一講書(shū)人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎吠架,沒(méi)想到半個(gè)月后芙贫,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡傍药,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年磺平,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拐辽。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拣挪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出俱诸,到底是詐尸還是另有隱情菠劝,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布乙埃,位于F島的核電站闸英,受9級(jí)特大地震影響锯岖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜甫何,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一出吹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧辙喂,春花似錦捶牢、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至炬太,卻和暖如春灸蟆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背亲族。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工炒考, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人霎迫。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓斋枢,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親知给。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瓤帚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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