與Binder相關(guān)的幾個類
可以參考類圖刚照,這些類的職責(zé)都在類圖中寫出來了
Binder的流程圖
光看這兩張圖蒿秦,可能對這些依然沒有什么概念具练,下面結(jié)合一個具體的AIDL例子合住,來具體看下這些類帘饶、流程都是怎么工作的哑诊。
AIDL的原理
看下面一個例子,我們先定義一個aidl接口及刻,然后綁定服務(wù)镀裤,在client中獲取該接口的實(shí)例:
// IMyAidlInterface.aidl
package com.example.myapplication.aidl;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void myTest(int anInt);
}
在需要的地方綁定服務(wù):
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 我們這里拿到的對象其實(shí)就是其Stub的內(nèi)部類Proxy對象
myAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private void bindAIDLService() {
Intent intent = new Intent();
bindService(intent, connection, BIND_AUTO_CREATE);
}
下面看一下編譯之后系統(tǒng)自動生成的java類竞阐,我們結(jié)合上面的兩張圖來理解Binder類的各個職責(zé)及流程:
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: D:\\Demo\\MyTest\\app\\src\\main\\aidl\\com\\example\\myapplication\\aidl\\IMyAidlInterface.aidl
*/
// Declare any non-default types here with import statements
public interface IMyAidlInterface extends android.os.IInterface {
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.myapplication.aidl.IMyAidlInterface {
// 描述符
private static final java.lang.String DESCRIPTOR = "com.example.myapplication.aidl.IMyAidlInterface";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.myapplication.aidl.IMyAidlInterface interface,
* generating a proxy if needed.
* 這里就是我們在將IBinder轉(zhuǎn)化為具體的aidl接口時調(diào)用的方法
*/
public static com.example.myapplication.aidl.IMyAidlInterface asInterface(android.os.IBinder obj) {
if ((obj==null)) {
return null;
}
// 先檢查本地是否有aidl對象,如果client和server在同一進(jìn)程暑劝,則會走進(jìn)這個回調(diào)
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.myapplication.aidl.IMyAidlInterface))) {
return ((com.example.myapplication.aidl.IMyAidlInterface)iin);
}
// 在不同進(jìn)程骆莹,就返回一個Proxy對象
return new com.example.myapplication.aidl.IMyAidlInterface.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
case TRANSACTION_myTest: {
data.enforceInterface(descriptor);
int _arg0;
_arg0 = data.readInt();
this.myTest(_arg0);
reply.writeNoException();
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
// 其實(shí)是Server在Client中的本地代理對象,實(shí)現(xiàn)了在aidl中定義的方法担猛,其實(shí)是將參數(shù)序列化
// 后幕垦,調(diào)用mRemote(也就是BinderProxy)去處理;一般情況下我們在綁定服務(wù)后傅联,拿到的遠(yuǎn)程對象先改,
// 就是這個Proxy
private static class Proxy implements com.example.myapplication.aidl.IMyAidlInterface {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
* 這個方法將參數(shù)序列化后,交給mRemote去處理蒸走,transact中傳入了每個參數(shù)對應(yīng)的編號仇奶;
* 這時,client調(diào)用方法線程會掛起比驻,等待server響應(yīng);
* 等服務(wù)端處理結(jié)束后该溯,將數(shù)據(jù)返回至binder驅(qū)動,后者喚醒掛起的線程别惦,這時一次跨進(jìn)程通信就完成了
*/
@Override public void myTest(int anInt) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
mRemote.transact(Stub.TRANSACTION_myTest, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_myTest = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public void myTest(int anInt) throws android.os.RemoteException;
}
可以看到狈茉,一共生成了三個類:
- IMyAidlInterface extends android.os.IInterface,client中獲取到的是這個接口步咪,用于client和server通信
- IMyAidlInterface.Stub
- IMyAidlInterface.Stub.Proxy:server的本地代理接口论皆,我們調(diào)用的方法都是由它來處理益楼,傳遞給binder對象的
下面我們將上面三個類單獨(dú)拆分出來看下
首先是繼承自IInterface接口的IMyAidlInterface接口猾漫,只聲明了一個方法,也就是我們定義的aidl方法
所有可以在Binder中傳輸?shù)慕涌诙夹枰^承自IInterface接口
public interface IMyAidlInterface extends android.os.IInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public void myTest(int anInt) throws android.os.RemoteException;
}
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.myapplication.aidl.IMyAidlInterface {
// 描述符感凤,Binder的唯一標(biāo)識
private static final java.lang.String DESCRIPTOR = "com.example.myapplication.aidl.IMyAidlInterface";
static final int TRANSACTION_myTest = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
/** Construct the stub at attach it to the interface. */
public Stub(){
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.myapplication.aidl.IMyAidlInterface interface,
* generating a proxy if needed.
* 這里就是我們在將IBinder轉(zhuǎn)化為具體的aidl接口時調(diào)用的方法
*/
public static com.example.myapplication.aidl.IMyAidlInterface asInterface(android.os.IBinder obj) {
if ((obj==null)) {
return null;
}
// 先檢查本地是否有aidl對象悯周,如果client和server在同一進(jìn)程,則會走進(jìn)這個回調(diào)
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.myapplication.aidl.IMyAidlInterface))) {
return ((com.example.myapplication.aidl.IMyAidlInterface)iin);
}
// 在不同進(jìn)程陪竿,就返回一個Proxy對象
return new com.example.myapplication.aidl.IMyAidlInterface.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder(){
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
case TRANSACTION_myTest: {
data.enforceInterface(descriptor);
int _arg0;
_arg0 = data.readInt();
this.myTest(_arg0);
reply.writeNoException();
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
}
這里的Stub就是一個Binder的子類禽翼,當(dāng)客戶端和服務(wù)端都處于同一個進(jìn)程時,方法調(diào)用不會走跨進(jìn)程的transact過程族跛,只有二者在不同進(jìn)程時闰挡,才會走transact,該過程由Proxy類來完成
- asInterface:用于將服務(wù)端的Binder對象轉(zhuǎn)化為客戶端所需的AIDL接口類型的對象礁哄;依然區(qū)分進(jìn)程长酗,如果是同進(jìn)程,那返回的是服務(wù)端的Stub本身桐绒,否則夺脾,返回的是封裝后的Stub.Proxy對象
- asBinder:返回當(dāng)前Binder對象
- onTransact:該方法運(yùn)行在服務(wù)端中的Binder線程池之拨,客戶端發(fā)起的遠(yuǎn)程請求會通過底層封裝后交給該方法來處理。服務(wù)端通過code參數(shù)可以確認(rèn)調(diào)用的是哪個方法咧叭,然后從data中取出參數(shù)蚀乔,執(zhí)行目標(biāo)方法; 當(dāng)目標(biāo)方法執(zhí)行完后菲茬,向reply中寫入返回值吉挣,再通過Binder返回給客戶端
// 其實(shí)是Server在Client中的本地代理對象,實(shí)現(xiàn)了在aidl中定義的方法婉弹,其實(shí)是將參數(shù)序列化
// 后听想,調(diào)用mRemote(也就是BinderProxy)去處理;一般情況下我們在綁定服務(wù)后马胧,拿到的遠(yuǎn)程對象汉买,
// 就是這個Proxy
private static class Proxy implements com.example.myapplication.aidl.IMyAidlInterface {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
* 這個方法將參數(shù)序列化后,交給mRemote去處理佩脊,transact中傳入了每個參數(shù)對應(yīng)的編號蛙粘;
* 這時,client調(diào)用方法線程會掛起威彰,等待server響應(yīng);
* 等服務(wù)端處理結(jié)束后出牧,將數(shù)據(jù)返回至binder驅(qū)動,后者喚醒掛起的線程歇盼,這時一次跨進(jìn)程通信就完成了
*/
@Override public void myTest(int anInt) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
mRemote.transact(Stub.TRANSACTION_myTest, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
- myTest:該方法運(yùn)行在客戶端舔痕,客戶端調(diào)用時,首先創(chuàng)建輸入?yún)?shù)_data豹缀,將對應(yīng)的參數(shù)寫入 _data,然后調(diào)用transact()方法發(fā)起遠(yuǎn)程調(diào)用伯复,然后當(dāng)前線程會掛起,服務(wù)端的transact方法得到調(diào)用返回結(jié)果后邢笙,該線程繼續(xù)執(zhí)行啸如,從 _reply中取出返回值并返回
注意
- 客戶端發(fā)起遠(yuǎn)程請求時,當(dāng)前線程會被掛起直到服務(wù)端返回?cái)?shù)據(jù)氮惯,如果一個遠(yuǎn)程方法可能是耗時的叮雳,那就不能在主線程中去發(fā)起調(diào)用
- 服務(wù)端的Binder方法是運(yùn)行在Binder線程池中的,因此binder方法無論耗時與否妇汗,都應(yīng)該采用同步的方法去實(shí)現(xiàn)帘不,因?yàn)樗呀?jīng)運(yùn)行在一個子線程中了