移步Android跨進(jìn)程通信IPC
簡(jiǎn)介
- Binder運(yùn)行在服務(wù)端進(jìn)程坷虑,如果服務(wù)端由于某種原因異常終止惫恼,這時(shí)候服務(wù)端和客戶(hù)端之間的Binder連接會(huì)斷裂也就是Binder死亡猜绣。這個(gè)時(shí)候如果再做遠(yuǎn)程調(diào)用就會(huì)失敗,進(jìn)而會(huì)導(dǎo)致客戶(hù)端的功能異常。我們可以給Binder設(shè)置一個(gè)死亡代理,當(dāng)Binder死亡時(shí)我們會(huì)收到通知回調(diào)毡证,在回調(diào)內(nèi)我們可以做重連操作以便恢復(fù)連接。
- 服務(wù)端直接調(diào)用客戶(hù)端內(nèi)方法獲取數(shù)據(jù)蔫仙,以便客戶(hù)端和服務(wù)端雙向交互料睛。
- 做一個(gè)觀察者模式,可以在服務(wù)端數(shù)據(jù)發(fā)生數(shù)據(jù)變化時(shí)及時(shí)通知客戶(hù)端摇邦。
1. 設(shè)置死亡代理
主要有兩個(gè)操作步驟恤煞,一是聲明死亡代理,并在Binder的死亡回調(diào)中做重連等相關(guān)操作施籍;二是設(shè)置死亡代理居扒。
1.1 聲明死亡代理
//實(shí)例化死亡代理接口,并實(shí)現(xiàn)死亡回調(diào)的接口
IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
//死亡回調(diào)的接口
@Override
public void binderDied() {
if (mRemoteService == null){
return;
}
//解綁死亡代理
mRemoteService.asBinder().unlinkToDeath(mDeathRecipient,0);
mRemoteService = null;
// TODO: 做重新綁定service服務(wù)丑慎,或者其他的操作
...
}
};
TODO部分自行做操作苔货,可以做和服務(wù)端的重連操作也可以做其他操作
1.2 設(shè)置死亡代理
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder serverBinder) {
mRemoteService = IService.Stub.asInterface(serverBinder);
try {
//給binder設(shè)置死亡代理
serverBinder.linkToDeath(mDeathRecipient,0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
上面部分的主要代碼前文中已經(jīng)做過(guò)解讀,此處不再贅述立哑。里面有一個(gè)額外的方法調(diào)用就是
serverBinder.linkToDeath()
,這個(gè)方法就是給Binder設(shè)置死亡代理姻灶,當(dāng)Binder異常死亡時(shí)就會(huì)調(diào)用mDeathRecipient內(nèi)的binderDied方法做死亡通知铛绰。
2. 設(shè)置客戶(hù)端和服務(wù)端雙向交互
做雙向交互要做的核心就是客戶(hù)端也要?jiǎng)?chuàng)建一個(gè)Binder對(duì)象并將Binder對(duì)象交付給服務(wù)端。其中觀察者模式使用的核心也是如此产喉。
2.1 客戶(hù)端內(nèi)創(chuàng)建Binder對(duì)象
創(chuàng)建回調(diào)使用的aidl
package com.wuyazhou.learn.IPC.aidl;
import com.wuyazhou.learn.IPC.aidl.Book;
interface ICallback {
void callback(in Book newBook);
}
客戶(hù)端內(nèi)創(chuàng)建Binder對(duì)象
private ICallback mCallback = new ICallback.Stub() {
@Override
public void callback(Book newBook) throws RemoteException {
Log.d("wuyazhouAIDL","回調(diào):"+newBook.bookName);
}
};
這里的Binder對(duì)象mCallback運(yùn)行在客戶(hù)端
2.2 將客戶(hù)端內(nèi)創(chuàng)建的Binder對(duì)象交付給服務(wù)端
mRemoteService.useCallback(mCallback);
2.3 服務(wù)端調(diào)用客戶(hù)端接口
private final IService.Stub mBinder = new IService.Stub() {
...
@Override
public void useCallback(ICallback callback) throws RemoteException {
callback.callback(new Book(456,"Android進(jìn)階"));
}
};
這里可能會(huì)疑惑為什么ICallback可以直接調(diào)用callback接口捂掰,并且能調(diào)用到客戶(hù)端內(nèi)實(shí)現(xiàn)的ICallback.aidl內(nèi)的接口敢会。
因?yàn)樯弦徊轿覀兺ㄟ^(guò)Binder的傳遞機(jī)制將Binder對(duì)象ICallback傳遞給了服務(wù)端,所以服務(wù)端持有ICallback的Binder这嚣。
3. 觀察者模式
觀察者模式和上面的雙向交互幾乎一致鸥昏,只是向多個(gè)客戶(hù)端分發(fā)和解綁操作,所以這里要有一個(gè)存儲(chǔ)向客戶(hù)端回調(diào)的接口的容器姐帚。因?yàn)榭蛻?hù)端將aidl的接口傳遞給Server時(shí)Server端會(huì)重新生成一個(gè)全新的對(duì)象吏垮,也就是說(shuō)解綁時(shí)我們傳遞要解綁的aidl接口也會(huì)生成一個(gè)全新的對(duì)象,這兩次生成的全新對(duì)象肯定是不一樣的對(duì)象罐旗,所以普通的容器不能滿(mǎn)足對(duì)aidl接口的對(duì)應(yīng)增刪膳汪。
RemoteCallbackList是系統(tǒng)專(zhuān)門(mén)提供的用于刪除跨進(jìn)程listener的接口。它的內(nèi)部有一個(gè)Map用來(lái)專(zhuān)門(mén)存儲(chǔ)AIDL回調(diào)九秀。其中key是IBinder類(lèi)型遗嗽,value是Callback類(lèi)型。
3.1 創(chuàng)建監(jiān)聽(tīng)使用的aidl
package com.wuyazhou.learn.IPC.aidl;
import com.wuyazhou.learn.IPC.aidl.Book;
interface IOnNewBookArrivedListener {
void onNewBookArrived(in Book newBook);
}
3.2 服務(wù)端接收和移除監(jiān)聽(tīng)
private final IService.Stub mBinder = new IService.Stub() {
/** 添加監(jiān)聽(tīng)*/
@Override
public void registerListener(IOnNewBookArrivedListener listener) {
mRemoteCallbackList.register(listener);
final int N = mRemoteCallbackList.beginBroadcast();
mRemoteCallbackList.finishBroadcast();
}
/** 移除監(jiān)聽(tīng)*/
@Override
public void unRegisterListener(IOnNewBookArrivedListener listener) {
mRemoteCallbackList.unregister(listener);
final int N = mRemoteCallbackList.beginBroadcast();
mRemoteCallbackList.finishBroadcast();
}
};
3.3 客戶(hù)端實(shí)現(xiàn)監(jiān)聽(tīng)
private IOnNewBookArrivedListener mOnNewBookArrivedListener = new IOnNewBookArrivedListener.Stub() {
@Override
public void onNewBookArrived(Book newBook) throws RemoteException {
Log.d("wuyazhouAIDL","有新書(shū)到了");
}
};
3.4 客戶(hù)端綁定監(jiān)聽(tīng)
mRemoteService.registerListener(mOnNewBookArrivedListener);
3.5 服務(wù)端分發(fā)監(jiān)聽(tīng)
private void onNewBookArrived(Book book) throws RemoteException {
final int N = mRemoteCallbackList.beginBroadcast();
for (int i = 0; i < N; i++) {
IOnNewBookArrivedListener l = mRemoteCallbackList.getBroadcastItem(i);
if (l != null) {
try {
l.onNewBookArrived(book);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
mRemoteCallbackList.finishBroadcast();
}
onNewBookArrived(new Book(123,"藝術(shù)探索"));