Messenger簡介 Messenger和AIDL是實現進程間通信(interprocess communication)的兩種方式. 實際上,Messenger的實現其實是對AIDL的封裝. Messenger適合於多進程單線程,AIDL適合於多進程多線程,需要開發者自己實現線程安全. goog ...
Messenger簡介
Messenger和AIDL是實現進程間通信(interprocess communication)的兩種方式.
實際上,Messenger的實現其實是對AIDL的封裝.
Messenger適合於多進程單線程,AIDL適合於多進程多線程,需要開發者自己實現線程安全.
google官方文檔指出對於大部分的程式,service不需要執行多線程,所以應該首先考慮使用Messenger.
為什麼需要進程間通信?
因為不同進程之間的數據是不共用的.
實踐(以音樂播放器demo為例)
關鍵詞: bind + messenger + handler
step1 (AndroidManifest.xml)在AndroidManifest.xml中註冊service,並設置為其android:process屬性賦值
註意① 忘記註冊service的話,程式不會響應,但是也不會崩潰的...
註意② 此處設置該service為一個全局進程,意即不同應用程式可以共用該進程,若process以":"開頭,則表示其為該應用程式的私有進程.
<service android:name=".MusicService"
android:process="com.example.janiszhang.musicplayer.service.process"/>
step2 (MusicService)在service中實現一個繼承Handler的子類(),用於處理由activity發來的message
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
mActivityMessenger = msg.replyTo;
switch (msg.what) {
case 0:
mMediaPlayer.stop();
i = msg.arg1;
mMediaPlayer = MediaPlayer.create(MusicService.this, mMusicDatas.get(i).getSrc());
if(isPlaying) {
mMediaPlayer.start();
}
//mRemoteViews.setTextViewText(R.id.music_name, mMusicDatas.get(i).getName());
//mRemoteViews.setTextViewText(R.id.singer_name, mMusicDatas.get(i).getSinger());
//mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
break;
case 1:
if(msg.arg1==1){
isPlaying =false;
mMediaPlayer.pause();
//mRemoteViews.setImageViewResource(R.id.btn_play, R.drawable.note_btn_play);
//mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
} else {
isPlaying = true;
i = msg.arg2;
mMediaPlayer = MediaPlayer.create(MusicService.this, mMusicDatas.get(i).getSrc());
mMediaPlayer.start();
//mRemoteViews.setImageViewResource(R.id.btn_play, R.drawable.note_btn_pause);
//mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
break;
default:
break;
}
}
}
step3 (MusicService)實例化自定義的handler,作為參數,創建一個Messenger
Messenger mMessenger = new Messenger(new IncomingHandler());
step4 (MusicService)實現onBind()方法
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
step5 (MusicActivity) 創建一個ServiceConnection實例,在onServiceConnected方法中獲取到service返回的messenger.
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMessenger = new Messenger(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
step6 (MusicActivity)bindservice
Intent intent = new Intent(this, MusicService.class);
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
step7 bind成功後,就可以獲取到一個Messenger的實例,通過該實例activity可以向另外一個進程中的service發送message,例如:
mNextBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mIndex = (mIndex+1)>=mMusicDatas.size()? 0 : mIndex+1;
setMusicNameAndSingerName(mIndex);
if(mMessenger != null) {
Message message = Message.obtain(null, 0);
message.arg1 = mIndex;
message.replyTo = mActivityMessenger;
try {
mMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
至此,基於Messenger的由activity到service的進程間通信就是實現完成了.
遇到的問題:
當我試圖Message實例的obj賦值為true時,會導致異常:
java.lang.RuntimeException: Can't marshal non-Parcelable objects across processes.
意思是說obj應該是一個實現了Parcelable介面的對象.
解決方案:對於這種情況,應該使用bundle來傳遞數據.
總結一下:
1.activity與service以bind的方式通信.
2.service中創建一個用於處理數據的handler,並以之為參數創建一個Messenger,通過onbind返回給activity.
3.activity使用service返回的Messenger實例send message
github地址:https://github.com/zhangbz/MusicPlayer