近日在作組件化方案時,複習了一遍Bidner機制,在熟悉了一遍Bidner機制後,對進程間通信以及Android設計模式原來有了較深的感悟。 Android Binder 是一個及其深刻的話題,從Linux間進程通訊的方式,到Android間通訊方式都須要瞭解,下圖是binder大體實現(看完我就暈了)。本文不經過複雜的代碼細節,以及底層代碼分析Binder實現方式。而是經過相對好理解的AIDL(也是大衆認爲的最好理解binder的方式)來熟悉binder。對AIDL不瞭解的朋友,可先行看下三步掌握Android中的AIDL來大體瞭解一下期使用方式。java
這裏咱們不講述上面複雜的實現。而是經過AIDL介紹binder的上層實現原理。Binder是Android中的一個類,它繼承了IBinder接口。android
下面是經過Aidl實現進程間通訊的簡化圖,您能夠不記住,這裏有個印象就好。設計模式
咱們先建立三個文件分別爲Market.java、 Market.aidl、ImarketManger.aidl文件 代碼以下:app
Market.java
ide
public class Market implements Parcelable {
private int goodsId;
private String goodsName;
public Market(int goodsId, String goodsName) {
this.goodsId = goodsId;
this.goodsName = goodsName;
}
protected Market(Parcel in) {
goodsId = in.readInt();
goodsName = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(goodsId);
dest.writeString(goodsName);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<Market> CREATOR = new Creator<Market>() {
@Override
public Market createFromParcel(Parcel in) {
return new Market(in);
}
@Override
public Market[] newArray(int size) {
return new Market[size];
}
};
}
複製代碼
Market.aidl
組件化
// Market.aidl
package com.ccdt.itvision.demo;
parcelable Market;
複製代碼
ImarketManger.aidl
ui
// IMarketManger.aidl
package com.ccdt.itvision.demo;
import com.ccdt.itvision.demo.Market;
// Declare any non-default types here with import statements
interface IMarketManger {
List<Market> getGoodList();
void addGoods(in Market market);
}
複製代碼
上面三個文件中,Market表示一個超市食物類,它實現了Parcelable接口。Market.aidl是Market類在AIDL中的聲明。IMarketManger.aidl是咱們本身定義的一個接口。裏面有兩個方法。而後咱們rebuild project
會在 app/build/generated/source/com.xxx.xxx/ 看見ImarketManger.java文件這個文件就是咱們研究的重中之重!它的所有代碼以下:this
public interface IMarketManger extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.ccdt.itvision.viewlearning.IMarketManger {
private static final java.lang.String DESCRIPTOR = "com.ccdt.itvision.demo.IMarketManger";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.ccdt.itvision.viewlearning.IMarketManger interface,
* generating a proxy if needed.
*/
public static com.ccdt.itvision.viewlearning.IMarketManger asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.ccdt.itvision.viewlearning.IMarketManger))) {
return ((com.ccdt.itvision.viewlearning.IMarketManger) iin);
}
return new com.ccdt.itvision.viewlearning.IMarketManger.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 {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getGoodList: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.ccdt.itvision.viewlearning.Market> _result = this.getGoodList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addGoods: {
data.enforceInterface(DESCRIPTOR);
com.ccdt.itvision.viewlearning.Market _arg0;
if ((0 != data.readInt())) {
_arg0 = com.ccdt.itvision.demo.Market.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addGoods(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.ccdt.itvision.viewlearning.IMarketManger {
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;
}
@Override
public java.util.List<com.ccdt.itvision.viewlearning.Market> getGoodList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.ccdt.itvision.viewlearning.Market> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getGoodList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.ccdt.itvision.viewlearning.Market.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addGoods(com.ccdt.itvision.viewlearning.Market market) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((market != null)) {
_data.writeInt(1);
market.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addGoods, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getGoodList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addGoods = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public java.util.List<com.ccdt.itvision.viewlearning.Market> getGoodList() throws android.os.RemoteException;
public void addGoods(com.ccdt.itvision.viewlearning.Market market) throws android.os.RemoteException;
}
複製代碼
看起來很複雜,但其實這個類邏輯仍是蠻清晰。咱們縮進下代碼在看。 spa
首先這裏聲明瞭兩個方法,getGoodList()
和
addGoods()
。這兩個方法顯然是咱們在ImarketManger中聲明的。而後是一個靜態的內部類Stub。stub繼承自Binder,顯然他本身就是一個Binder類。當客戶端和服務端都位於同一個進程時,方法調用不會走跨進程的transact過程,而當二者位於不一樣進程時,方法調用須要走transact過程,這個邏輯由Stub的內部代理類Proxy來完成。因此這裏的核心就是Stub的內部代理Proxy。Proxy內部方法以下:
用於將服務端的Binder對象轉換成客戶端所需的AIDL接口類型的對象,這種轉換過程是區分進程的,若是客戶端和服務端位於同一進程,那麼此方法返回的就是服務端的Stub對象自己,不然返回的是系統封裝後的Stub.proxy對象。線程
此方法用於返回當前Binder對象
此方法運行在服務端中的Binder線程池中,當客戶端經過aidl發起跨進程請求時,遠程請求會經過系統底層封裝後交由此方法來處理。服務端經過code能夠肯定客戶端所請求的方法是什麼,接着從data中取出該方法所需的參數(沒參數則不取),而後執行該方法。當該方法執行完畢後,就向reply中寫入返回值,這就是onTransact的執行過程。值得注意的是,若是此方法返回false,那麼客戶端的請求會失敗
首先建立該方法所須要的輸入型Parcel對象_data、輸出型Parcel對象_reply。 聲明返回值對象List。 _data.writeInterfaceToken(DESCRIPTOR); 將該方法所需參數信息寫入data 中。 接着調用transact方法來發起RPC(遠程過程調用)請求,當前線程hang on(掛起),當服務端 onTransact(剛介紹完的方法,回頭去看一看)執行完畢後。從_reply中取出RPC過程的返回結果處理完畢。
經過以上分析,下面咱們在回頭看剛剛的簡圖是否是就明朗了許多?
從上述分析過程來看,咱們徹底能夠不提供AIDL文件便可實現Binder,之因此提供AIDL文件,是爲了方便系統爲咱們生成代碼。系統根據AIDL文件生成Java文件的格式是固定的,咱們能夠不用AIDL文件直接寫一個Binder出來。
首先聲明一個接口繼承 IInterface
代碼以下:
public interface IMarketManger extends IInterface {
static final String DESCRIPTOR = "com.ccdt.itvision.demo.custombinder.IMarketManger";
static final int TRANSACTION_getGoodList = IBinder.FIRST_CALL_TRANSACTION + 0;
static final int TRANSACTION_addGood = IBinder.FIRST_CALL_TRANSACTION+1;
public List<Market> getGoodList() throws RemoteException;
public void addGoods(Market market) throws RemoteException;
}
複製代碼
接着,建立ImarketManger的實現類,實現思路與AIDL生成的代碼相似。若是服務端使用手寫Binder,只須要在onBinder的時候返回ImarketManger的實現類就好。代碼以下:
public class MarketImpl extends Binder implements IMarketManger {
public MarketImpl() {
this.attachInterface(this, DESCRIPTOR);
}
public static IMarketManger asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IInterface iInterface = obj.queryLocalInterface(DESCRIPTOR);
if (iInterface != null && iInterface instanceof IMarketManger) {
return (IMarketManger) iInterface;
}
return new MarketImpl.Proxy(obj);
}
@Override
public List<Market> getGoodList() throws RemoteException {
return null;
}
@Override
public void addGoods(Market good) throws RemoteException {
}
@Override
public IBinder asBinder() {
return this;
}
@Override
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
switch (code) {
case INTERFACE_TRANSACTION:
reply.writeString(DESCRIPTOR);
return true;
case TRANSACTION_getGoodList:
data.enforceInterface(DESCRIPTOR);
List<Market> goodList = this.getGoodList();
reply.writeNoException();
reply.writeTypedList(goodList);
return true;
default:
break;
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements IMarketManger {
private IBinder mRemote;
public Proxy(IBinder obj) {
mRemote = obj;
}
@Override
public List<Market> getGoodList() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
List<Market> result;
try {
data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(TRANSACTION_getGoodList, data, reply, 0);
reply.readException();
result = reply.createTypedArrayList(Market.CREATOR);
} finally {
reply.recycle();
data.recycle();
}
return result;
}
@Override
public void addGoods(Market market) throws RemoteException {
// TODO: 與aidl中同樣
}
@Override
public IBinder asBinder() {
return mRemote;
}
}
複製代碼
Aidl只是Google爲咱們實現Binder 實現的一個簡便方式生成模板化代碼,事實上咱們徹底能夠這樣手寫一個aidl,這有利於咱們理解Bidner的實現方式。另外Binder還有個重要的方法,Linktodeath()
因服務端的狀況咱們未知,可能出現異常狀況,當binder 死亡時,咱們能夠經過binder死亡代理 知道連接已經斷開,從新綁定連接。
最後Binder的實現機制看似複雜,可是其中頗有條理,若是你想使用組件化方案,瞭解android底層原理,作framwork層代碼,binder 使咱們繞不開的話題,因此先在Aidl開始瞭解並深刻,對您的成長是很是有意義的!