1. 定義IBookManager接口
public interface IBookManager extends IInterface {
static final java.lang.String DESCRIPTOR = "qingfengmy.developmentofart._2activity.Manual.IBookManager";
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
public java.util.List<qingfengmy.developmentofart._2activity.aidl.Book> getBookList() throws android.os.RemoteException;
public void addBook(qingfengmy.developmentofart._2activity.aidl.Book book) throws android.os.RemoteException;
}
聲明一個aidl性質(zhì)的接口,只需要繼承IInterface接口(接口繼承接口)。定義兩個業(yè)務(wù)方法和對應(yīng)的ID,以及binder特有的唯一標(biāo)識符DESCRIPTOR,一般為完整類名。
2. 實現(xiàn)Stub類
public class BookManagerImpl extends Binder implements IBookManager {
/**
* Construct the stub at attach it to the interface.
* 構(gòu)建連接到接口的stub
*/
public BookManagerImpl() {
this.attachInterface(this, DESCRIPTOR);
}
@Override
public List<Book> getBookList() throws RemoteException {
// 待實現(xiàn)
return null;
}
@Override
public void addBook(Book book) throws RemoteException {
// 待實現(xiàn)
}
@Override
public IBinder asBinder() {
return this;
}
}
3. 添加Stub的子類Proxy
/**
* Cast an IBinder object into an IBookManager interface,
* generating a proxy if needed.
* <p/>
* 客戶端連接服務(wù)端會通過該方法獲得Binder,根據(jù)是否跨應(yīng)用會返回IBookManager或者代理Proxy.
* 跨應(yīng)用時返回代理,客戶端拿到代理,調(diào)用方法時,實際是transact方法去調(diào)用onTransact的。
*/
public static IBookManager asInterface(IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof IBookManager))) {
return ((IBookManager) iin);
}
return new BookManagerImpl.Proxy(obj);
}
private static class Proxy implements IBookManager {
private IBinder mRemote;
Proxy(IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public java.util.List<Book> getBookList() throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
List<Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addBook(Book book) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book != null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
4. onTransact方法
Binder中的方法定義
/**
* Default implementation is a stub that returns false. You will want
* to override this to do the appropriate unmarshalling of transactions.
*
* <p>If you want to call this, call transact().
*/
protected boolean onTransact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {}
如果要調(diào)用binder中的onTransact方法,調(diào)用transact即可。transact是IBinder中定義的方法,Binder實現(xiàn)了IBinder,所以也有transact方法。如下
/**
* Default implementation rewinds the parcels and calls onTransact. On
* the remote side, transact calls into the binder to do the IPC.
*/
public final boolean transact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
if (false) Log.v("Binder", "Transact: " + code + " to " + this);
if (data != null) {
data.setDataPosition(0);
}
boolean r = onTransact(code, data, reply, flags);
if (reply != null) {
reply.setDataPosition(0);
}
return r;
}
可見其中調(diào)用了onTransact方法,在方法之前和之后做了處理。之前把輸入型對象data的dataPosition設(shè)為0;之后把輸出型對象reply的dataPosition設(shè)為0.
transact翻譯為辦理,binder在里面處理業(yè)務(wù)。根據(jù)code判斷是哪個方法,data是輸入型,reply是輸出型。
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getBookList: {
data.enforceInterface(DESCRIPTOR);
List<Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
Book _arg0;
if ((0 != data.readInt())) {
_arg0 = Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
開發(fā)中我們可以使用aidl,aidl的意義在于為我們提供了一種快速實現(xiàn)Binder的工具。它不是實現(xiàn)Binder的必須品,我們可以手寫B(tài)inder。
5. 本應(yīng)用使用自定義的Binder
public class ManualService extends Service {
// 服務(wù)中的binder是private
private BookManagerImpl bookManager;
public ManualService() {
bookManager = new BookManagerImpl();
}
@Override
public IBinder onBind(Intent intent) {
return bookManager;
}
}
public class ManualActivity extends AppCompatActivity {
ServiceConnection serviceConnection;
// 接口是暴露出來的
IBookManager bookManager;
Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_manual);
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
bookManager = BookManagerImpl.asInterface(service);
Log.e("aaa","-----onServiceConnected-----");
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
intent = new Intent(this, ManualService.class);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}
// click-調(diào)用getBookList方法
bookManager.getBookList();
// onDestroy
}
6. 跨應(yīng)用調(diào)用服務(wù)
和aidl一樣,首先創(chuàng)建包名類名一樣的幾個文件
qingfengmy.developmentofart._2activity.aidl.Book
qingfengmy.developmentofart._2activity.Manual.BookManagerImpl
qingfengmy.developmentofart._2activity.Manual.IBookManager
客戶端調(diào)用
IBookManager iBookManager;
ServiceConnection serviceConnection;
Intent intent;
intent = new Intent();
intent.setAction("qingfengmy.developmentofart.ManualService");
intent.setPackage("qingfengmy.developmentofart");
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (service != null) {
iBookManager = BookManagerImpl.asInterface(service);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
bindService(intent, serviceConnection, Service.BIND_AUTO_CREATE);
// click點擊事件調(diào)用服務(wù)端方法
iBookManager.getBookList();
7. likeToDeath和unlikeToDeath
Binder運(yùn)行在服務(wù)端,如果服務(wù)端進(jìn)程由于某種原因異常終止,這個時候我們連接服務(wù)端的Binder連接斷裂(稱之為Binder死亡),會導(dǎo)致我們的遠(yuǎn)程調(diào)用失敗。
如果我們不知道Binder連接已經(jīng)斷裂,那么客戶端的功能就會受影響。解決方法是給Binder設(shè)置死亡代理,當(dāng)Binder死亡時,我們就會收到通知,這個時候我們就可以重新發(fā)起連接請求從而恢復(fù)連接。
// 定義死亡代理 recipient翻譯為收件人
final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
// binder死亡時,會回調(diào)這個方法
if (bookManager == null){
return;
}
bookManager.asBinder().unlinkToDeath(this,0);
bookManager = null;
// 重連
bindService(intent,serviceConnection,BIND_AUTO_CREATE);
}
};
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
bookManager = BookManagerImpl.asInterface(service);
// 設(shè)置死亡代理
service.linkToDeath(mDeathRecipient,0);
}
@Override
public void onServiceDisconnected(ComponentName name) {}
};
8. isBinderAlive
該方法用于判斷Binder的狀態(tài)
bookManager.asBinder().isBinderAlive();