天天看點

随筆Android IPC程序通信之——Messenger

随筆Android IPC程序通信之——Messenger

android中用于程序通信和資料共享的方式有多種,最基本的Bundle,檔案共享,Messenger,AIDL,ContentProvider,Socket等,他們的差別和使用場景這裡就不再說了,詳情自行檢視了解了解,本文直接介紹方式之一Messenger(信使)的使用方式。

代碼為例,開始看看我們遇到的問題,模拟多程序資料同步問題

1.建立一個IPCDemo,建立一個自己的Applciation并聲明一個公用變量value

随筆Android IPC程式通信之——Messenger

2.建立兩個Activity,在第一個MainActivity中修改Oncreate中修改 Application中value值為8

随筆Android IPC程式通信之——Messenger

由MainActivity進入第二個頁面(服務Activity)注意此activity在Manifest中配置中添加android:process=”:remote”,目的是讓其單獨運作在一個程序中,和MainActivity不同程序。

随筆Android IPC程式通信之——Messenger

在ServerActivity中我們同樣列印Applcation中的value;

結果如下:

随筆Android IPC程式通信之——Messenger

3.引起的問題 我們知道一個應用中Application是一個重量級的,由系統建立的單一執行個體,其中的資料是共享的,那麼這裡我們在MainActivity中修改了value值,這個應用中的其他通路的地方應該都是修改後的值,但上面的結果卻不是這樣。

原因就在于,我們的ServerActivity配置了android:process=":remote",這會導緻ServerActivity運作在另一程序中,說白了就是,MainActivity是一個應用,ServerActivity是一個應用,既然是兩個不同應用,那麼就會有兩個不同的Application執行個體,Application會建立多次(這裡兩次),這兩個執行個體分别位于不同程序(應用中),這就是為什麼修改第一個全局值,而第二個程序中的值沒有任何影響的原因。
           

4.解決問題 我們如何讓第一個程序修改變量值的時候,通知另一個程序同步修改對應的值?接下來就利用本文介紹的Messenger。

Messenger 運用

messenger 其實是基于消息的程序通信方式,最基本的了解就是有用戶端,服務端如下圖:

随筆Android IPC程式通信之——Messenger

接下來代碼介紹:

我們的MainActivity用來充當用戶端,ServerActivity充當服務端,因為兩個頁面完全運作在不同的程序中。

首先,建立一個MessengerService,并在manifest中配置成和ServerActivity中相同的程序。代碼如下:

/**
 * Created by Frosty on //.
 *//

public class    MessengerService extends Service{
    public static String TAG = MessengerService.class.getSimpleName();
    public final static int FROM_CLIENT = ;//來此用戶端請求
    public final static int FROM_SERVICE= ;//來此服務端請求
    private Messenger msngerCurrent;//目前類使用(發送消息、接收處理消息)

    @Override
    public void onCreate() {
        super.onCreate();
        msngerCurrent = new Messenger(new MessengerHandler());
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return msngerCurrent.getBinder();
    }

    public static class MessengerHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case FROM_CLIENT:

                    ///.處理接受消息
                    Log.e(TAG,"收到來自用戶端【"+msg.getData().getString("name")+"】的消息:"+msg.getData().getString("content"));

                    MyApplication.value = msg.getData().getInt("value");

                    //.拿到用戶端發送消息附帶的Messenger,用它回傳消息
                    Messenger msngerReply = msg.replyTo;
                    //封裝回傳消息
                    Message replyMsg = Message.obtain(null,FROM_SERVICE);
                    Bundle bundle = new Bundle();
                    bundle.putString("name","阿裡雲");
                    bundle.putString("content","你好,我這邊已經同步修改,值為:"+MyApplication.value);
                    replyMsg.setData(bundle);
                    try {
                        msngerReply.send(replyMsg);//回傳消息
                    }catch (Exception e){}
                    break;

                default:break;
            }
        }
    }
}
           
這裡暫時隻說明這個服務的功能,利用MessengerHandler處理發送自用戶端來的資料,通過msg.what比對。
           

是以我們在用戶端(MainActivity中去注冊綁定這個服務,并在修改appvalue時候發送一個消息給這個服務)

public class MainActivity extends AppCompatActivity {

    private Messenger msngerCurrent;
    private class MessengerHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MessengerService.FROM_SERVICE:
                    Log.e("MessengerService","收到來自服務端【"+msg.getData().getString("name")+"】的回應:"+msg.getData().getString("content"));
                    unbindService(serviceConnection);
                    break;
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MyApplication.value = ;//此處修改值

        Log.e("appvalue","MainActivity中擷取到的value:"+MyApplication.value);
        /*綁定服務*/
        bindRemoteService();
        msngerCurrent = new Messenger(new MessengerHandler());
        findViewById(R.id.btn_requestServer).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,ServerActivity.class);
                startActivity(intent);
            }
        });
    }



    ///服務連結狀态監聽
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Messenger messengerClient = new Messenger(service);
            /*封裝消息體*/
            Message msg = Message.obtain(null,MessengerService.FROM_CLIENT);//對應服務端接受碼
            Bundle bundle = new Bundle();
            bundle.putString("name","張山");
            bundle.putString("content","我修改了我們的共享值,請你務必修改!");
            bundle.putInt("value",MyApplication.value);
            msg.setData(bundle);
            msg.replyTo=msngerCurrent;
            //發送
            try{
                messengerClient.send(msg);
            }catch (Exception e){
            }
        }

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

    public void bindRemoteService(){
        Intent intent = new Intent(this, MessengerService.class);
        bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
    }


    @Override
    protected void onDestroy() {
        unbindService(serviceConnection);
        super.onDestr

oy();
    }
}
           

我們詳細解釋一下工作流程

- 我們首先得建立一個ServiceConnection 用于檢測服務綁定後或者斷開後的操作如下圖,綁定服務連結後,回掉調nServiceConnected方法,在這個方法中,我們構造一個用戶端Messenger

随筆Android IPC程式通信之——Messenger

并用message封裝資料,然後用這個Messenger發送消息即可

發送消息後,MessengerService便可以接收到消息處理,修改目前程序的appvalue值,并回傳附加消息給用戶端,注意這裡回傳的Messenger,直接在擷取消息體中用msg.replyTo擷取,前提是用戶端相應的在傳過來的msg中replyTo指派Mesenger,此messenger在用戶端也用來處理服務端響應回來的資料。

随筆Android IPC程式通信之——Messenger

5.結果 我們重新開機應用,重新列印兩個值

随筆Android IPC程式通信之——Messenger

發現在主程序修改appvalue後,另一個程序擷取到的值也及時得到同步了。

End注意:Messenger通信,可使用它進行程序間的通信,而Messenger對Service的請求采用隊列的方式,是以它不支援多線程通信。

繼續閱讀