寫(xiě)在前面
創(chuàng)新互聯(lián)專(zhuān)業(yè)為企業(yè)提供劍川網(wǎng)站建設(shè)、劍川做網(wǎng)站、劍川網(wǎng)站設(shè)計(jì)、劍川網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)與制作、劍川企業(yè)網(wǎng)站模板建站服務(wù),十多年劍川做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。
Binder是Android給我們提供的一種跨進(jìn)程通信方式。理解Binder能幫助我們更好的理解Android的系統(tǒng)設(shè)計(jì),比如說(shuō)四大組件,AMS,WMS等系統(tǒng)服務(wù)的底層通信機(jī)制就都是基于Binder機(jī)制的。當(dāng)然了,Binder機(jī)制的底層驅(qū)動(dòng)實(shí)現(xiàn)很復(fù)雜,本文的目的只是為了理清Binder的使用和在應(yīng)用層的結(jié)構(gòu)和流程,對(duì)于Binder在底層是如何實(shí)現(xiàn)的,目前能力還沒(méi)到這一步去分析,不會(huì)涉及到。對(duì)于這部分,不妨將它看成是一個(gè)黑盒子,我們輸入什么,然后底層會(huì)給我們提供什么。
代理模式
我們知道,A進(jìn)程如果想要執(zhí)行B進(jìn)程的b方法,是沒(méi)辦法直接辦得到的,但是通過(guò)Binder機(jī)制,B進(jìn)程可以返回給A進(jìn)程一個(gè)代理對(duì)象Proxy,然后A進(jìn)程通過(guò)調(diào)用Proxy的方法,由Proxy幫我們將信息傳遞給B進(jìn)程,從而間接調(diào)用b方法。沒(méi)錯(cuò),Binder實(shí)現(xiàn)過(guò)程中用到了代理模式。所以在繼續(xù)前行之前,有必要簡(jiǎn)單了解下代理模式先。
代理模式相對(duì)來(lái)說(shuō)好理解一些,因?yàn)樵谏钪校教幎加写淼挠白樱热缯f(shuō)我們想去香港買(mǎi)個(gè)Mac,但是自己不方便去,于是我們找了代購(gòu);比如說(shuō)現(xiàn)在年底了要搶火車(chē)票,但是在12306手動(dòng)搶票根本搶不到啊,所以我們找了第三方搶票軟件,它會(huì)每隔幾十ms就幫我們查詢(xún)一次,有票的話就幫我們下單。這里就以搶火車(chē)票為例來(lái)說(shuō)明代理模式的結(jié)構(gòu)。

proxy
模式比較簡(jiǎn)單,就直接上代碼了。
// 聲明買(mǎi)票接口
public interface ITicket {
boolean buyTicket();
}
// 官方的12306
public class Real12306 implements ITicket {
@Override
public boolean buyTicket() {
if (搶票成功) return true;
return false;
}
}
// 第三方搶票軟件
public class ThirdParty12306 implements ITicket {
private Real12306 real12306;
public ThirdParty12306(Real12306 real12306) {
this.real12306 = real12306;
}
@Override
public boolean buyTicket() {
while (true) {
if (real12306.buyTicket()) {
return true;
}
// 10ms查詢(xún)一次結(jié)果
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
// 初始化我們的購(gòu)票信息
Real12306 real12306 = new Real12306();
ThirdParty12306 thirdParty12306 = new ThirdParty12306(real12306);
// 開(kāi)始不斷搶票,釋放我們的勞動(dòng)力
thirdParty12306.buyTicket();
}
}使用了代理模式之后,我們就不用時(shí)時(shí)刻刻盯著12306刷票了,只需要把這些重復(fù)無(wú)聊的工作交給代理去幫我們干就好了。
AIDL
一般來(lái)說(shuō),我們使用Binder都是通過(guò)AIDL來(lái)完成的。我們新建一個(gè)aidl文件,然后定義一個(gè)接口,這樣Android Studio就會(huì)幫我們生成一個(gè)java接口文件。以一個(gè)最簡(jiǎn)單的接口來(lái)說(shuō)吧。
package example.com.aidl;
interface IMath {
int add(int a, int b);
}生成的IMath.java文件中,代碼有點(diǎn)亂,整理一下之后,結(jié)構(gòu)大致是這樣子的:

aidl
簡(jiǎn)單來(lái)說(shuō),生成了一個(gè)IMath接口,接口內(nèi)定義了一個(gè)抽象類(lèi)IMath.Stub,繼承了Binder,IMath.Stub又有一個(gè)內(nèi)部類(lèi)IMath.Stub.Proxy。IMath.Stub和IMath.Stub.Proxy都實(shí)現(xiàn)了IMath這個(gè)接口。結(jié)合上面的代理模式,從這里我們就可以猜出,在跨進(jìn)程通信中,由于各個(gè)進(jìn)程都是獨(dú)立的,我們的客戶(hù)端拿不到服務(wù)端的IMath.Stub類(lèi),只能獲得它的代理IMath.Stub.Proxy,再通過(guò)它來(lái)間接幫我們?cè)L問(wèn)IMath.Stub類(lèi),從而完成跨進(jìn)程通信。
Binder流程
看了上面的結(jié)構(gòu)圖之后,估計(jì)大家還是看不懂的。不急,我們?cè)俳Y(jié)合上面這個(gè)例子來(lái)說(shuō)明。Binder機(jī)制是基于C/S模型的,也就是說(shuō),需要一個(gè)client進(jìn)程和一個(gè)Server進(jìn)程。Client和Server是相對(duì)的,誰(shuí)發(fā)消息,誰(shuí)就是Client,誰(shuí)接收消息,誰(shuí)就是Server。在實(shí)際開(kāi)發(fā)中,Server進(jìn)程通常是四大組件中的Service(Service必須在Manifest文件中指定進(jìn)程名字)。
class RemoteService : Service() {
val math = Math()
override fun onCreate() {
super.onCreate()
Log.d(TAG, "onCreate")
}
override fun onBind(intent: Intent): IBinder {
return math
}
inner class Math : IMath.Stub() {
override fun add(a: Int, b: Int): Int {
return a + b
}
}
}在RemoteService中,我們先定義一個(gè)Math類(lèi),繼承自IMath.Stub,在這里實(shí)現(xiàn)我們具體的服務(wù)端邏輯。因?yàn)镮Math.Stub繼承自Binder,Binder又實(shí)現(xiàn)了IBinder接口,所以在onBind()方法中直接返回math對(duì)象。接著再來(lái)看客戶(hù)端的業(yè)務(wù)邏輯。
// 定義ServiceConnection類(lèi)
inner class MyServiceConnection : ServiceConnection {
override fun onServiceDisconnected(name: ComponentName?) {
Log.d(TAG, "onServiceDisconnected")
}
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
if (service == null) return
// 將IBinder轉(zhuǎn)換成IMath
math = IMath.Stub.asInterface(service)
Log.d(TAG, "result is ${math.add(1, 2)}")
}
}
// 在onCreate中綁定RemoteService
val intent = Intent(this, RemoteService::class.java)
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)當(dāng)連接上Service后,就會(huì)回調(diào)客戶(hù)端的onServiceConnected()方法,這里傳進(jìn)來(lái)的service是一個(gè)BinderProxy對(duì)象。
BinderProxy是Binder的代理類(lèi),同樣也實(shí)現(xiàn)了IBinder接口。我們?cè)赟erver端返回的明明是一個(gè)Math對(duì)象,到這里就變成了BinderProxy對(duì)象了,是不是有點(diǎn)神奇?別忘了,Math本身就是一個(gè)Binder對(duì)象。由于是跨進(jìn)程通信,我們無(wú)法直接拿到這個(gè)Binder對(duì)象,只能由BinderProxy對(duì)象來(lái)幫助我們完成任務(wù)。至于Binder是怎么變成BinderProxy的,這就是Binder機(jī)制的底層原理了,將它當(dāng)成一個(gè)黑盒子就好了。
拿到BinderProxy對(duì)象后,再將它轉(zhuǎn)換成我們定義的IMath接口。
// IMath.java
private static final java.lang.String DESCRIPTOR = "example.com.aidl.IMath";
public static example.com.aidl.IMath asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof example.com.aidl.IMath))) {
return ((example.com.aidl.IMath) iin);
}
return new example.com.aidl.IMath.Stub.Proxy (obj);
}
// Binder.java
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
if (mDescriptor != null && mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}從asInterface()方法中可以看到,根據(jù)Key值DESCRIPTOR在Binder中匹配mOwner,它是一個(gè)IInterface對(duì)象。但既然是去取值,就應(yīng)該有地方將他們存進(jìn)來(lái)的,我們好像錯(cuò)過(guò)了什么。這里還得回到Math的初始化過(guò)程,Math繼承自IMath.Stub,看一下它的構(gòu)造方法就能明白了。
// IMath.java
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
// Binder.java
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}到了這里,IInterface的獲取已經(jīng)很明顯了吧。但其實(shí),這里取出來(lái)的是Null。What?為什么?別忘了,RemoteService是運(yùn)行在一個(gè)單獨(dú)的進(jìn)程中的,attachInterface()方法是Binder調(diào)用的。而我們的客戶(hù)端拿到的只是BinderProxy,查詢(xún)到的IInterface當(dāng)然是Null了,所以我們還得接著看asInterface()方法。(當(dāng)然了,如果RemoteService和客戶(hù)端運(yùn)行在同一個(gè)進(jìn)程的話,這里就能直接拿到IInterface了,但這與跨進(jìn)程通信就沒(méi)有半毛錢(qián)關(guān)系了。)
return new example.com.aidl.IMath.Stub.Proxy(obj);
直接返回了一個(gè)代理對(duì)象。后續(xù)我們要跟Server端做交互就得靠它了。比如我們調(diào)用了Proxy.add()方法:
@Override
public int add(int a, int b) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain ();
int _result;
try {
// 使用Parcel來(lái)寫(xiě)入數(shù)據(jù)以便于跨進(jìn)程傳輸
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(a);
_data.writeInt(b);
// mRemote是在asInterface中獲得的BinderProxy對(duì)象
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
// 使用Parcel來(lái)接收返回值
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}核心方法是mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);。這里的mRemote是客戶(hù)端拿到的BinderProxy對(duì)象,然后就要開(kāi)始跨進(jìn)程傳輸了。又到了黑盒子出現(xiàn)的時(shí)候了,客戶(hù)端發(fā)起跨進(jìn)程通信后,服務(wù)端就會(huì)在自己進(jìn)程的onTranscat()方法中收到通知:
@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_add : {
data.enforceInterface(descriptor);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
} default: {
return super.onTransact(code, data, reply, flags);
}
}
}在Server端收到信息后,會(huì)先通過(guò)Parcel將信息解析出來(lái),然后執(zhí)行我們調(diào)用的add()方法,也就是我們?cè)赗emoteService中重寫(xiě)IMath.Stub的add()方法。最后將結(jié)果寫(xiě)回Parcel中再跨進(jìn)程傳回給客戶(hù)端,從而完成了一次跨進(jìn)程通信。
如果看到這里,對(duì)于Binder的流程還有疑惑的話,那就再來(lái)一張時(shí)序圖好了。

binder
看圖說(shuō)話,當(dāng)我們?cè)诳蛻?hù)端中去bindService()的時(shí)候,Server端在onBind()中返回了一個(gè)Binder對(duì)象,經(jīng)過(guò)Binder驅(qū)動(dòng)的轉(zhuǎn)換,這個(gè)Binder到了客戶(hù)端中變成了BinderProxy,客戶(hù)端接著再把BinderProxy轉(zhuǎn)換成Stub.Proxy,后面我們與Server的跨進(jìn)程通信就都是通過(guò)Stub.Proxy發(fā)起的,然后Binder驅(qū)動(dòng)會(huì)幫我們將數(shù)據(jù)跨進(jìn)程傳輸給真正的Binder,Binder執(zhí)行完操作后再將結(jié)果寫(xiě)入由Binder驅(qū)動(dòng)傳回來(lái)。由此完成了一次跨進(jìn)程通信。
從圖中我們也可以看出通信過(guò)程是同步的。當(dāng)客戶(hù)端發(fā)起請(qǐng)求的同時(shí),當(dāng)前的線程會(huì)被掛起,直到結(jié)果返回。所以要注意的是如果請(qǐng)求太耗時(shí)的話,不應(yīng)該在主線程中去請(qǐng)求,否則容易出現(xiàn)ANR。給個(gè)Systrace直觀感受一下。

Systrace
相應(yīng)的CPU信息是處于休眠狀態(tài)的。

cpu
最后
掌握了Binder的上層原理之后,后面再來(lái)深入Framework層學(xué)習(xí)就會(huì)簡(jiǎn)單一些,這篇文章也是為了后面的學(xué)習(xí)打下基礎(chǔ)。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)創(chuàng)新互聯(lián)的支持。
分享標(biāo)題:AndroidBinder入門(mén)學(xué)習(xí)筆記
分享URL:http://chinadenli.net/article26/iigscg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)建站、響應(yīng)式網(wǎng)站、網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)公司、、域名注冊(cè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)