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