2025-04-23

如果你需要你的service與遠程進程通信,那麼你可以使用一個Messenger來為你的service提供接口.此技術使用不必使用AIDL就能執行進程間通信(IPC).

  下面是如何使用Messenger的概要:

service實現一個接收從客戶端的每個調用引起的回調的Handler.

Handler被用來創建一個Messenger對象(它是Handler的一個引用).

Messenger創建一個從service的onBind()返回給客戶端的IBinder.

客戶端使用IBinder來實例化這個Messenger(它引用到service的Handler),客戶端用它來向service發送Message.

service在它的Handler中接收每個消息—具體的,是在handleMessage()方法中.

  這此方式下,service中沒有能讓客戶端調用的方法,客戶端傳送的是service在它的Handler中接收的"消息"(Message對象).

下面是一個service使用Messenger接口的例子:

[java] public class MessengerService extends Service { 
    /** 讓service 顯示一個消息的命令 */ 
    static final int MSG_SAY_HELLO = 1; 
 
    /**
     * 處理從客戶端來的消息.
     */ 
    class IncomingHandler extends Handler { 
        @Override 
        public void handleMessage(Message msg) { 
            switch (msg.what) { 
                case MSG_SAY_HELLO: 
                    Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show(); 
                    break; 
                default: 
                    super.handleMessage(msg); 
            } 
        } 
    } 
 
    /**
     * 我們發佈給客戶端使它能向IncomingHandler 發送消息的的對象
     */ 
    final Messenger mMessenger = new Messenger(new IncomingHandler()); 
 
    /**
     * 當綁定到service,我們返回指向我們的messenger的接口
     */ 
    @Override 
    public IBinder onBind(Intent intent) { 
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); 
        return mMessenger.getBinder(); 
    } 

public class MessengerService extends Service {
    /** 讓service 顯示一個消息的命令 */
    static final int MSG_SAY_HELLO = 1;

    /**
     * 處理從客戶端來的消息.
     */
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     * 我們發佈給客戶端使它能向IncomingHandler 發送消息的的對象
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());

    /**
     * 當綁定到service,我們返回指向我們的messenger的接口
     */
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        return mMessenger.getBinder();
    }
}

 

 

註意Handler中的handleMessage()方法是service接收消息並進行處理的地方.

  客戶端所有要做的事就是創建一個基於service返回的IBinder的Messenger對象並且使用它的send()發送一個消息.如,下面是一個actvity綁定到service並且傳送MSG_SAY_HELLO命令給service的例子:

[java] public class ActivityMessenger extends Activity { 
    /** 與service通信的Messenger */ 
    Messenger mService = null; 
 
    /** 表明我們是否已綁定到service的標記 */ 
    boolean mBound; 
 
    /**
     *與service的主接口交互的類
     */ 
    private ServiceConnection mConnection = new ServiceConnection() { 
        public void onServiceConnected(ComponentName className, IBinder service) { 
            // 當與service的連接已經建立時被調用.給瞭我們可以用來  
            //與service交互的對象.我們正在使用一個Messenger與service通信,  
            // 所以在這裡我們從原始IBinder 對象獲取一個客戶端的Messenger的代表  
            mService = new Messenger(service); 
            mBound = true; 
        } 
 
        public void onServiceDisconnected(ComponentName className) { 
            // 當與service的連接意外斷開時被調用– 也就是,service的進程崩潰瞭  
            mService = null; 
            mBound = false; 
        } 
    }; 
 
    public void sayHello(View v) { 
        if (!mBound) return; 
        // 創建並發送一個消息給service  
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); 
        try { 
            mService.send(msg); 
        } catch (RemoteException e) { 
            e.printStackTrace(); 
        } 
    } 
 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
    } 
 
    @Override 
    protected void onStart() { 
        super.onStart(); 
        // 綁定到service  
        bindService(new Intent(this, MessengerService.class), mConnection, 
            Context.BIND_AUTO_CREATE); 
    } 
 
    @Override 
    protected void onStop() { 
        super.onStop(); 
        // Unbind from the service  
        if (mBound) { 
            unbindService(mConnection); 
            mBound = false; 
        } 
    } 

public class ActivityMessenger extends Activity {
    /** 與service通信的Messenger */
    Messenger mService = null;

    /** 表明我們是否已綁定到service的標記 */
    boolean mBound;

    /**
     *與service的主接口交互的類www.aiwalls.com
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            // 當與service的連接已經建立時被調用.給瞭我們可以用來
            //與service交互的對象.我們正在使用一個Messenger與service通信,
            // 所以在這裡我們從原始IBinder 對象獲取一個客戶端的Messenger的代表
            mService = new Messenger(service);
            mBound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            // 當與service的連接意外斷開時被調用– 也就是,service的進程崩潰瞭
            mService = null;
            mBound = false;
        }
    };

    public void sayHello(View v) {
        if (!mBound) return;
        // 創建並發送一個消息給service
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
        try {
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

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

    @Override
    protected void onStart() {
        super.onStart();
        // 綁定到service
        bindService(new Intent(this, MessengerService.class), mConnection,
            Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }
}

註意這個例子沒有演示service如何回應客戶端.如果你想讓service回應客戶端,那麼你需要在客戶端也創建一個Messanger.然後當客戶端接收到onServiceConnected()回調時,它發送一個息給service,這個消息包含瞭客戶端的Messenger對象,它作為send()方法的replyTo參數.

 

比較 AIDL
  當你需要執行IPC時,為你的接口使用一個Messenger比使用AIDL實現它簡單,因為Messenger把所有對service的調用入隊列,一個純AIDL接口並行發送請求到service,這樣就必須用多線程來處理瞭.

  對於大多數應用,service不需使用多線程,所以使用一個Messenger允許service在一個時刻隻處理一個請求.如果使用多線程對你的service很重要,那麼你應使用AIDL來定義你的接口.

 摘自  nkmnkm的專欄 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *