Messenger實現Activity與Service的雙向通訊
Activity與Service間的單向通訊,相信大家都知道,常用的有下面3種方式:
1. 通過bindService(service, conn, BIND_AUTO_CREATE)開啟Service,然後在ServiceConnection的onServiceConnected回撥方法中獲取到Service引用,然後我們就可以訪問Service中的方法了.
2. 通過broadcast(廣播)的形式,當開啟的Service接收到了對應的廣播,就可以處理預設好的邏輯了.
3. 通過呼叫類名直接呼叫Service中定義的靜態方法.
今天要將的是解決Activity與Service的雙向通訊的問題,即Activity可以呼叫Service中暴露的方法,同時Service也可以呼叫Activity中暴露的方法.
實現的方式:
Messenger+Handler.
原理:
分別將Activity和Service的引用傳送給對方,通過Handler物件來發送引用,在Activity與Service中都定義一個Handler.
關鍵問題,如何拿到對方的Handler來發送引用?
通過Messenger類,他可以把一個Handler轉換成IBinder,也可以把IBinder轉換成Messenger.
下面將通過一個Demo來展示Messenger的使用.
目標Activity
public class AudioPlayerActivity extends BaseActivity {
private AudioPlayerService mAudioPlayerService;
//Service拿到這個handler就可以與Activity通訊了
private Handler mActivityHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
LogUtils.i(AudioPlayerActivity.this, ">>>>>>>>>>>handleMessage...what=" + msg.what + " obj=" + msg.obj);
switch (msg.what) {
case AudioPlayerService.SERVICE_INTERFACE:
//獲取AudioPlayerService的引用
mAudioPlayerService = (AudioPlayerService) msg.obj;
mAudioPlayerService.testCallService();
break;
}
}
};
private Messenger mActivityMessenger = new Messenger(mActivityHandler);
@Override
protected void setTitleBar(TitleBar titleBar) {
titleBar.setTitleBarBgResource(R.drawable.base_titlebar_bg);
titleBar.setLeftIcon(R.drawable.selector_btn_back, new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
titleBar.setCenterTv("最炫民族風");
}
@Override
protected boolean isHomePage() {
return false;
}
@Override
public Integer getLayoutResId() {
return R.layout.activity_audio_player;
}
@Override
public void initView() {
}
@Override
public void initListener() {
}
@Override
public void initData() {
Intent intent = getIntent();
if (null != intent) {
Bundle bundle = intent.getExtras();
if (null == bundle && bundle.size() < 0) {
mLoadView.setExceptionViewVisible(true);
} else {
//直接把bundle通過引數傳到服務中,然後在service中取出來
Intent service = new Intent(this, AudioPlayerService.class);
service.putExtras(bundle);
//先通過start方式開啟服務,保證服務能工作在後臺
startService(service);
//再通過bind的方式開啟服務,保證activity能夠和service間互動
bindService(service, conn, BIND_AUTO_CREATE);
}
}
}
/**
* 服務聯結器
*/
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
LogUtils.i(AudioPlayerActivity.this, ">>>>>>>>>>>onServiceConnected");
//注意:這裡的binder是由AudioPlayerService的mServiceMessenger.getBinder()返回的,因此這裡使用binder建立Messenger的話,就可以公用AudioPlayerService的Handler傳送訊息了.
Messenger messenger = new Messenger(binder);
Message msg = Message.obtain();
msg.what = AudioPlayerService.UI_INTERFACE;
msg.obj = AudioPlayerActivity.this; //這裡將AudioPlayerActivity的引用傳送給AudioPlayerService
msg.replyTo = mActivityMessenger;// 將Activity中的mActivityMessenger傳遞個Service
LogUtils.i(AudioPlayerActivity.this, "replyTo>>>>>>>>>>>" + mActivityMessenger);
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
LogUtils.i(AudioPlayerActivity.this, ">>>>>>>>>>>onServiceDisconnected");
}
};
public void updateUI(Audio audio) {
LogUtils.i(AudioPlayerActivity.this, ">>>>>>>>>>>updateUI");
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
@Override
public void reLoadData() {
}
@Override
public void onClick(View v) {
}
}
目標Service
public class AudioPlayerService extends Service {
public static final int UI_INTERFACE = 0; //獲取AudioPlayerActivity引用的message what
public static final int SERVICE_INTERFACE = 1; //獲取AudioPlayerService引用的message what
private int mPosition;
private ArrayList<Parcelable> mAudioList;
private static AudioPlayerActivity mAudioPlayerActivity;
private static Messenger mActivityMessenger;
//Activity拿到這個handler就可以與service通訊了
private Handler mServiceHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case UI_INTERFACE:
//拿到AudioPlayerActivity的引用
mAudioPlayerActivity = (AudioPlayerActivity) msg.obj;
mAudioPlayerActivity.updateUI(null);
//拿到AudioPlayerActivity的mActivityMessenger物件,來發送訊息給mActivityHandler
mActivityMessenger = msg.replyTo;
Message message = Message.obtain();
message.what = SERVICE_INTERFACE;
message.obj = AudioPlayerService.this;
LogUtils.i(AudioPlayerService.this, "mActivityMessenger>>>>>>>>>>>" + mActivityMessenger);
try {
mActivityMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
};
//建立Messenger物件
Messenger mServiceMessenger = new Messenger(mServiceHandler);
@Override
public void onCreate() {
LogUtils.i(AudioPlayerService.this, ">>>>>>>>>>>onCreate");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
LogUtils.i(AudioPlayerService.this, ">>>>onBind");
return mServiceMessenger.getBinder();//返回一個Binder
}
public void testCallService() {
LogUtils.i(AudioPlayerService.this, ">>>>>>>>>>>testCallService");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
LogUtils.i(AudioPlayerService.this, ">>>>>>>>>>>onStartCommand");
// //獲取Activity傳遞過來的資料
Bundle bundle = intent.getExtras();
mPosition = bundle.getInt(Constant.KEY_POSITION);
mAudioList = bundle.getParcelableArrayList(Constant.KEY_LIST);
LogUtils.i(AudioPlayerService.this, "mPosition:" + mPosition + " mAudioList:" + mAudioList);
return super.onStartCommand(intent, flags, startId);
}
}
列印的日誌
I/AudioPlayerService: >>>>>>>>>>>onCreate
I/AudioPlayerService: >>>>>>>>>>>onStartCommand
I/AudioPlayerService: >>>>onBind
I/AudioPlayerActivity: >>>>>>>>>>>onServiceConnected
I/AudioPlayerActivity: replyTo>>>>>>>>>>>[email protected]
I/AudioPlayerActivity: >>>>>>>>>>>updateUI
I/AudioPlayerService: mActivityMessenger>>>>>>>>>>>[email protected]
I/AudioPlayerActivity: >>>>>>>>>>>handleMessage…what=1 obj=mchenys[email protected]41b072a8
I/AudioPlayerService: >>>>>>>>>>>testCallService
通過上面的日誌,可以發現AudioPlayerService成功的呼叫了AudioPlayerActivity的updateUI方法,同時AudioPlayerActivity也成功的呼叫了AudioPlayerService的testCallService方法.