如果你需要你的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.2cto.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的專欄