1. 程式人生 > >Android程序間的通訊之Messenger

Android程序間的通訊之Messenger

Android AIDL和Messenger區別

使用Messenger是執行程序間通訊最簡單的方法,因為Messenger會在單一執行緒中建立包含所有請求的佇列,這樣您就不必對服務進行執行緒安全設計。而純粹的AIDL介面會同時向服務傳送多個請求,服務隨後必須應對多執行緒處理。

AIDL通常應用在服務被設計到單獨的應用中的場景(即服務端可客戶端不屬於同一個app的情況),而Messenger通常應用在同一app的不同程序的場景中。

Messenger基本思想

服務端(被動方)提供一個Service來處理客戶端(主動方)連線,維護一個Handler(具體來講:是Handler的子類)來建立Messenger,在onBind時返回Messenger的binder(呼叫Messenger的getBinder()方法,該方法返回一個IBinder物件,客戶端將通過該物件作為引數建立一個Messenger物件用於與服務端進行通訊)。

Messenger使用步驟

1、服務端實現一個Handler,由其接收來自客戶端的每個呼叫的回撥
2、使用第1步的Handler的例項作為target建立Messenger物件(即該Messenger持有了對Handler的引用)
3、使用Messenger建立一個IBinder(通過呼叫Messenger的getBinder()方法),服務端的onBind()方法中將其返回到客戶端
4、客戶端使用IBinder將Messenger(引用服務端的Handler例項)例項化,然後使用後者將Message物件傳送給服務端
5、服務端在其Handler中接收每個Message

這樣,客戶端並沒有呼叫服務端的“方法”,而客戶端傳遞的訊息(Message物件)是服務端在其Handler中接收到的。

如果想讓服務端對客戶端發回響應,則還需要在客戶端中建立一個持有客戶端Handler實現類的Messenger,當客戶端收到onServiceConnected()回撥時,在向服務傳送的Message時,send()方法的replyTo引數中需包含客戶端的Messenger。這樣,客戶端就可在其Handler實現類中接收到來自服務端的響應訊息。

簡單示例

AndroidMainfest.xml

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label
="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="yf.exam.client.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".MessengerService" android:process=":custom_process"/> </application>

佈局檔案很簡單,這裡只有一個按鈕,用於向服務端傳送訊息並顯示服務端響應內容,這裡不再給出。

客戶端:MainActivity

public class MainActivity extends Activity {
    private static final int REPLY_MSG_ID = 2;
    private boolean mServiceConnected = false;
    private Button btn = null;
    //用於向Service端傳送訊息的Messenger
    private Messenger mBoundServiceMessenger = null;
    //用於接收Service傳送訊息的Messenger
    private final Messenger mReceiveMessenger = new Messenger(new ReceiveMessHandler(this));
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName name) {
            mBoundServiceMessenger = null;
            mServiceConnected = false;
        }
        
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBoundServiceMessenger = new Messenger(service);
            mServiceConnected = true;
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn = (Button)findViewById(R.id.button);
        bindService(new Intent(this, MessengerService.class), conn, Context.BIND_AUTO_CREATE);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mServiceConnected){
                    //獲取訊息物件
                    Message msg = Message.obtain(null, 1, 0, 0);
                    try{
                        //replyTo引數包含客戶端Messenger
                        msg.replyTo = mReceiveMessenger;
                        //向Service端傳送訊息
                        mBoundServiceMessenger.send(msg);
                    }catch(RemoteException re){
                        re.printStackTrace();
                    }
                }
            }
        });
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(mServiceConnected){
            unbindService(conn);
            mServiceConnected = false;
        }
    }
    /**
     * 客戶端實現一個Handler用於接收服務端返回的響應
     * @author Administrator
     *
     */
    static class ReceiveMessHandler extends Handler{
        //持有當前Activity的弱引用,避免記憶體洩露
        private final WeakReference<MainActivity> mActivity;
        public ReceiveMessHandler(MainActivity activity){
            mActivity = new WeakReference<MainActivity>(activity);
        }
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what){
            case REPLY_MSG_ID:
                Toast.makeText(mActivity.get(), msg.getData().getString("msg"), Toast.LENGTH_SHORT).show();
                break;
            }
        }
    }
}

服務端:MessengerService.java

public class MessengerService extends Service {
    private static final int REPLY_MSG_ID = 2;
    private static final int MSG_ID = 1;
    static class BoundServiceHandler extends Handler{
        private final WeakReference<MessengerService> mService;
        public BoundServiceHandler(MessengerService service){
            mService = new WeakReference<MessengerService>(service);
        }
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what){
            case MSG_ID:
                Messenger replyMessenger = msg.replyTo;
                Message replyMsg = Message.obtain(null, REPLY_MSG_ID);
                //向客戶端響應的訊息內容
                Bundle b = new Bundle();
                b.putString("msg", "this is the message reply from service");
                replyMsg.setData(b);
                try{
                    replyMessenger.send(replyMsg);
                }catch(RemoteException re){
                    re.printStackTrace();
                }
                break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
    private final Messenger mMessenger = new Messenger(new BoundServiceHandler(this));
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        return mMessenger.getBinder();
    }
}

此外,上述例子中所有的Handler的實現類都被宣告為static並使用Service或Activity的WeakReference。如果不這樣做,編譯器會給出警告資訊“This handler class should be static or leaks might occur”。通過使用弱引用的方式,就允許Service或Activity進行垃圾收集了。