天天看點

Android 利用Messenger進行跨程序通信

Messenger通信原理

Messenger其實是谷歌對aidl進行的封裝,用來處理簡單的跨程序通信。那麼如何用Messenger傳遞資訊呢?

單向通信

現在假設我們有服務端和用戶端,并且服務端與用戶端不在同一程序中。

     首先服務端需要建立一個Handler用來接收用戶端發送來的消息,然後利用這個handler,來構造一個Messenger,并且在onBind方法中将messenger的IBinder傳回給用戶端。那麼當用戶端通過bindService方法綁定這個服務之後,就可以通過這個IBinder對象來構造一個Messenger對象,然後就可以發送Message類型的消息,進而實作一個單向跨程序通信。

這麼說可能有些抽象,下面我貼上實作代碼,看完就應該很容易了解了。

//服務端代碼

RemoteService.class

public class RemoteService extends Service {
    private static final String TAG = "RemoteService";
    private Handler receiveHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 0:
                    Log.d(TAG,"收到了用戶端發來的消息:" + msg.getData().getString("client_message"));
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    };
    //這裡利用一個Handler對象構造一個Messenger對象
    private Messenger messenger = new Messenger(receiveHandler);
    public RemoteService() {
    }

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

這裡要注意,由于示範的是跨程序通信,但是為了友善我并沒有寫兩個應用,而是在service的配置中開了一個程序

AndroidManifest.xml

<service
            android:process=":remote"
            android:name=".service.RemoteService"
            android:enabled="true"
            android:exported="true"></service>
           

//用戶端代碼

MainActivity.class

public class MainActivity extends AppCompatActivity {

    private Messenger messenger;
    private ServiceConnection mConnection = new ServiceConnection(){
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //這裡利用一個IBinder對象構造一個Messenger對象
            messenger = new Messenger(service);
            Message msg = Message.obtain(null, 0);
            Bundle bundle = new Bundle();
            bundle.putString("client_message","I'm from Client!");
            msg.setData(bundle);
            try {
                messenger.send(msg);
            } 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);

        final Intent intent = new Intent(this, RemoteService.class);

        //綁定服務按鈕
        Button btnBind = (Button) findViewById(R.id.btn_bind);
        btnBind.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                bindService(intent, mConnection, BIND_AUTO_CREATE);
            }
        });
    }
}
           

當我們點選綁定服務按鈕時,控制台就會輸出一條資訊:

D/RemoteService: 收到了用戶端發來的消息:I'm from Client!。

下面說一下雙向通信:

    要實作雙向通信,那麼用戶端也需要建立一個Handler對象來接收服務端發來的消息。

        然後同樣,利用這個Handler對象來構造一個Messenger對象,并且在給服務端發消息時,

給Message對象的replyTo屬性指派,也就是msg.replyTo = clientMessenger;

那麼服務端如何給用戶端發消息呢?

其實很容易,就是利用剛才的msg.replyTo來擷取用戶端Messenger,然後發送消息。

    雙向通信代碼(跨程序)

//服務端代碼

RemoteService.class

public class RemoteService extends Service {
    private static final String TAG = "RemoteService";
    private Handler receiveHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 0:
                    Log.d(TAG,"收到了用戶端發來的消息:" + msg.getData().getString("client_message"));
                    //在這裡得到用戶端的Messenger
                    Messenger clientMessenger = msg.replyTo;
                    Message msg1 = Message.obtain(null, 0);
                    Bundle bundle = new Bundle();
                    bundle.putString("server_message","I'm from Server!");
                    msg1.setData(bundle);
                    try {
                        clientMessenger.send(msg1);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    };

    private Messenger messenger = new Messenger(receiveHandler);
    public RemoteService() {
    }

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

//用戶端代碼

MainActivity.class

public class MainActivity extends AppCompatActivity {

    private Messenger messenger;
    private ServiceConnection mConnection = new ServiceConnection(){
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //這裡利用一個IBinder對象構造一個Messenger對象
            messenger = new Messenger(service);
            Message msg = Message.obtain(null, 0);
            Bundle bundle = new Bundle();
            bundle.putString("client_message","I'm from Client!");
            msg.setData(bundle);
            //這裡就是把用戶端的Messenger傳遞過去
            msg.replyTo = clientMessenger;
            try {
                messenger.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    private Handler clientHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 0:
                    Log.d("MainActivity","收到了服務端傳回的消息:"+msg.getData().getString("server_message"));
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    };

    private Messenger clientMessenger = new Messenger(clientHandler);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Intent intent = new Intent(this, RemoteService.class);

        //綁定服務按鈕
        Button btnBind = (Button) findViewById(R.id.btn_bind);
        btnBind.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                bindService(intent, mConnection, BIND_AUTO_CREATE);
            }
        });
    }
}
           

當我們點選綁定服務按鈕時,控制台就會輸出這兩條資訊:

D/RemoteService: 收到了用戶端發來的消息:I'm from Client!。

D/MainActivity: 收到了服務端傳回的消息:I'm from Server!

繼續閱讀