Android中的IPC方式-Messenger

  1. IPC簡介

    IPC,即Inter-Process Communication進程間通信或者跨進程通信,是指兩個進程之間進行數據交換的過程。
    android中的IPC方式有很多種,以下是幾個簡單的對比:

    這裏寫圖片描述

    以上幾種各有利弊,可能我們平時用的多的還是Bundle、文件共享、AIDL、ContentProvider這幾種,對於Messenger這種方式很少用,而本章內容爲了彌補這塊的缺憾特寫此貼,希望我們的知識又能擴展擴展,不好勿噴。

  2. Messenger

    Messenger可以翻譯爲信使,通過它可以在不同進程中傳遞Message對象,這時候可能會聯想到咱們之前學的Handler對象,只不過Handler對象主要是進行線程間的數據通信的,而現在的Messenger則是進程間的通信的。

    Messenger是一種輕量級的IPC方案,它的底層實現是AIDL;它實際上是對AIDL的一種封裝。

    下面是Messenger類的繼承關係:

    這裏寫圖片描述

    使用Messenger與之前使用的Handler類似,同樣分爲服務端和客戶端。

    • 服務端進程
      拿Service舉例,需要創建一個Messenger對象,用於接收Activity中發送過來的消息,服務端代碼如下:
    public class MyService extends Service{

    private Messenger messenger;
    private Handler handler;

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
        handler = new Handler(new Handler.Callback() {

            @Override
            public boolean handleMessage(Message msg) {
                // TODO Auto-generated method stub
                //獲取從Activity中發送過來的消息
                Bundle bundle = msg.getData();
                String str = bundle.getString("msg");
                System.out.println("----->>"+str);

                //回執消息 即服務器收到消息之後可以反向給客戶端發送消息
                Messenger servi = msg.replyTo;//獲得從客戶端傳過來的信使對象Messenger

                Message reMsg = Message.obtain();
                Bundle bundle2 = new Bundle();
                bundle2.putString("msg", "消息回來了");
                reMsg.setData(bundle2);
                try {
                    servi.send(reMsg);//向Activity中發送回執消息
                } catch (RemoteException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                return false;
            }
        });
        //通過Handler對象創建一個Messenger對象
        messenger = new Messenger(handler);
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        //從Messenger對象中獲取IBinder對象並返回
        return messenger.getBinder();
    }
}
備註:此處的replyTo主要是爲了反向傳輸數據,即Service向ACtivity發送數據,Service中需要獲得Activity創建的Messenger對象,用於消息的發送。

- 客戶端進程
相當於綁定服務的Activity對象,首先需要綁定服務端的Service,成功後用服務端返回的IBinder對象創建一個Messenger,通過這個Messenger就可以向服務端發送消息了。

public class MessengerActivity extends Activity{
    private Messenger messenger,replyMessenger;
    private Handler handler;

    private ServiceConnection conn = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // TODO Auto-generated method stub
            //服務綁定成功之後 通過返回的IBinder對象創建Messenger對象 用於消息的發送
            messenger = new Messenger(service);
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_b);

        handler = new Handler(new Handler.Callback() {

            @Override
            public boolean handleMessage(Message msg) {
                // TODO Auto-generated method stub
                //獲取從Service中發送過來的數據
                Bundle bundle = msg.getData();
                String str = bundle.getString("msg");
                System.out.println("======>>>>"+str);
                return false;
            }
        });
        //創建一個Messenger對象 用於接收從Service中發送過來的消息
        replyMessenger = new Messenger(handler);

        //啓動服務 採用的是bindService的方式
        Intent intent = new Intent(this, MyService.class);
        bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        //解綁服務對象
        unbindService(conn);
    }

    public void onMyClick(View v) {
        if (messenger != null) {
            //構建要發送的Message消息
            Message msg = Message.obtain();
            Bundle bundle = new Bundle();
            bundle.putString("msg", "hello word");
            msg.setData(bundle);

            msg.replyTo = replyMessenger;//如果想收到服務器向客戶端發送過來的消息 必須把回執類傳遞給服務類

            try {
                messenger.send(msg);//發送消息 向存活在另一進程的service
            } catch (RemoteException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

總結上述代碼的工作原理,如下圖所示:

這裏寫圖片描述

注意:在AndroidManifest.xml文件中爲了更能體現進程間的通信,可將Service註冊爲遠程服務:即

<service android:name="com.example.exampledemo.MyService"
            android:process=":remote"></service>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章