天天看點

Android程序間通訊之messenger

平時一說程序間通訊(IPC),大家都會想到AIDL,其實messenger和AIDL作用一樣,都可以進行程序間通訊。它是基于消息的程序間通信,就像子線程和UI線程發送消息那樣,是不是很簡單,還不用去寫AIDL檔案,是不是很爽。

此外,還支援記錄用戶端對象的Messenger,然後可以實作一對多的通信;甚至作為一個轉接處,任意兩個程序都能通過服務端進行通信。

與 AIDL 比較:

  當您需要執行 IPC 時,為您的接口使用 Messenger 要比使用 AIDL 實作更加簡單,因為 Messenger 會将所有服務調用排入隊列,而純粹的 AIDL 接口會同時向服務發送多個請求,服務随後必須應對多線程處理。

  對于大多數應用,服務不需要執行多線程處理,是以使用 Messenger 可讓服務一次處理一個調用。如果您的服務必須執行多線程處理,則應使用 AIDL 來定義接口。

接下來看下怎麼用:

服務端:

1.建立一個handler對象,并實作hanlemessage方法,用于接收來自用戶端的消息,并作處理

2.建立一個messenger(送信人),封裝handler 

3.用messenger的getBinder()方法擷取一個IBinder對象,通過onBind傳回給用戶端

用戶端:

1.在activity中綁定服務

2.建立ServiceConnection并在其中使用 IBinder 将 Messenger執行個體化 

3.使用Messenger向服務端發送消息

4.解綁服務

5.服務端中在 handleMessage() 方法中接收每個 Message

這樣,用戶端并沒有調用服務的“方法”。而用戶端傳遞的“消息”(Message 對象)是服務在其 Handler 中接收的。

上面實作的僅僅是單向通信,即用戶端給服務端發送消息,如果我需要服務端給用戶端發送消息又該怎樣做呢?

其實,這也是很容易實作的,下面就讓我們接着上面的步驟來實作雙向通信吧

1.在用戶端中建立一個Handler對象,用于處理服務端發過來的消息

2.建立一個用戶端自己的messenger對象,并封裝handler。

3.将用戶端的Messenger對象賦給待發送的Message對象的replyTo字段

4.在服務端的Handler處理Message時将用戶端的Messenger解析出來,并使用用戶端的Messenger對象給用戶端發送消息

這樣就實作了用戶端和服務端的雙向通信了。

注意:注:Service在聲明時必須對外開放,即android:exported="true"

其實messenger底層也是AIDL。用戶端和服務端通訊,就是普通的AIDL,用戶端執行個體化stub之後,通過stub的send方法把消息發到服務端。服務端和用戶端通訊:服務端通過解析message的replyto,獲得用戶端的stub,然後通過send方法發送到用戶端。

用戶端:

package com.example.ipc_messenger;

import android.content.ComponentName;
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.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity1";
    private boolean mBond;
    private Messenger serverMessenger;
    private MyConn conn;
    //在用戶端中建立一個Handler對象,用于處理服務端發過來的消息

    private Messenger mMessenger = new Messenger(new Handler(){
        @Override
        public void handleMessage(Message msg) {
            Toast.makeText(getApplicationContext(),"收到用戶端的消息,内容是:"+msg.arg1,Toast.LENGTH_SHORT).show();
            super.handleMessage(msg);
        }
    });

    private class MyConn implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //連接配接成功
            serverMessenger = new Messenger(service);
            Log.i("Main", "服務連接配接成功");
            mBond = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            serverMessenger = null;
            mBond = false;
        }
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //綁定服務
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.example.ipc_messenger", "com.example.ipc_messenger.MyService"));
        conn = new MyConn();
        bindService(intent, conn, BIND_AUTO_CREATE);
        Button button = (Button) findViewById(R.id.bt1);
        //用戶端給伺服器發消息
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message toServiceMessage = Message.obtain();
                toServiceMessage.what = 1;
                toServiceMessage.arg1 = 12345;
                try {
                    //将用戶端的Messenger對象賦給待發送的Message對象的replyTo字段
                    toServiceMessage.replyTo = mMessenger;
                    serverMessenger.send(toServiceMessage);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    protected void onDestroy() {
        if (mBond) {
            unbindService(conn);
        }
        super.onDestroy();
    }
}
           

服務端:

package com.example.ipc_messenger;

import android.app.Service;
import android.content.Intent;
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 android.widget.Toast;

public class MyService extends Service {
    private static final String TAG = "MyService1";
    private static final int CODE = 1;
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
//        throw new UnsupportedOperationException("Not yet implemented");
        Log.d(TAG, "onBind: ");
        return mMessenger.getBinder();
    }
    //建立一個送信人,封裝handler
    private Messenger mMessenger = new Messenger(new serviceHandler());

    public class serviceHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            Message toClientMessage = Message.obtain();
            switch (msg.what) {
                case CODE:
                    //接收來自用戶端的消息,并作處理
                    int arg = msg.arg1;
                    Log.d(TAG, "handleMessage: msg.arg1="+msg.arg1);
                    Toast.makeText(getApplicationContext(),"收到用戶端的消息,内容是:"+arg+"" , Toast.LENGTH_SHORT).show();
                    //在服務端的Handler處理Message時将用戶端的Messenger解析出來,并使用用戶端的Messenger對象給用戶端發送消息
                    toClientMessage.arg1 = 1111111111;
                    try {
                        //回複用戶端消息
                        msg.replyTo.send(toClientMessage);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
            }
            super.handleMessage(msg);
        }
    }
}