綁定本地service并通訊
在service中定義Binder類璃赡,Binder類方法中可以訪問service的信息,在service的onbind返回binder類遥倦。
activity在它的serviceconnection.onserviceconected方法中會獲得onbind返回的binder對象谤绳,從而訪問service信息。
所以對本地service來說,binder對象就是service返回的代理對象袒哥,客戶端可以通過它反問service內(nèi)部數(shù)據(jù)缩筛,從而實現(xiàn)客戶端和service之間的通訊。
如果我們有一個接口提供服務(wù)堡称,接口一定是抽象的瞎抛,可以在service中創(chuàng)建實現(xiàn)接口的binder類,達到服務(wù)的目的却紧,剩下的和上面的相同桐臊,返回這個binder類為客戶端提供服務(wù)。
如果service想進行高消耗行為晓殊,可以繼承intentservice方法断凶,可以進行串聯(lián)耗時工作,但不支持并發(fā)挺物。
并發(fā)需要添加handle
onStartCommand返回值
如果service不在同一線程需要AIDL
首先將接口AIDL化懒浮,AIDL會自動生成java文件。
之后服務(wù)端修改binder類繼承AIDL.stub识藤,它是繼承了binder類并且實現(xiàn)了AIDL接口砚著。
客戶端通過AIDL.Stub.asInterface(service)獲得binder。
binder和service痴昧,IPC之間關(guān)系
service通信采用Ibinder通信,Ibinder也主要用于service稽穆,包含兩種,一種是本地通信赶撰,另一種是多進程通信舌镶,也就是IPC柱彻。
實現(xiàn)Ibinder可以3種方法,繼承Binder類餐胀,多進程通信可以采用AIDL和Messanger
其實AIDL也是繼承Binder類哟楷。
Messenger核心,Message以及Handler否灾。
首先服務(wù)端創(chuàng)建一個Handler卖擅,里面有handleMessage處理客戶端
之后使用回調(diào)的Handler創(chuàng)建一個Messenger,Messenger(Handler){Handle.getIMessenger()}
在onbind方法中返回底層的binder Messenger.getBinder().
客戶端的onServiceConnected通過傳過去的Ibinder創(chuàng)建Messenger(Ibinder){IMessenger.Stub.asInterface(Ibinder)},之后通過Messenger傳遞Message墨技。
使用的載體what,arg1,arg2,Bundle以及replyTo
如果需要服務(wù)端對客戶端進行回復(fù)惩阶,客戶端定義一個reHandler,利用這個Handler創(chuàng)建一個reMessenger,設(shè)置msg.replyto=reMessenger指定回復(fù)接收消息者,之后通過seMessenger發(fā)送信息扣汪,seMessenger收到信息断楷,seHandle處理,通過reMessenger.send 發(fā)送
可以看出Messenger就是一個收件地址
AIDL步驟
服務(wù)端創(chuàng)建AIDL文件包含接口崭别,在service中實現(xiàn)這些接口
客戶端綁定服務(wù)端冬筒,將onServiceConnection得到的Ibinder轉(zhuǎn)化為AIDL生成的Iinterface實例,通過實例調(diào)用方法紊遵。
Messenger和AIDL
Messenger串聯(lián)AIDL并發(fā)
service生命周期
onUnbind返回true調(diào)用onRebind,onRebind返回空值账千,但可以接收Ibinder
false調(diào)用onBind
AIDL流程
AIDL創(chuàng)建以后客戶端服務(wù)端都要有
創(chuàng)建的接口繼承了IInterface
服務(wù)端
- 重寫AIDL.Stub中的方法侥蒙,具體實現(xiàn)BookManager.stub mBookManager = new BookManager.stub() 并在內(nèi)部實現(xiàn)具體方法暗膜。也可以服務(wù)端新建繼承Stub類
- onBind中返回AIDL.Stub
客戶端
AIDL.Stub.asInterface(service)獲得binder。
AIDL源碼分析
客戶端分析
asInterface傳參Ibinder返回stub
先判定是否在同一進程鞭衩,如果是学搜,返回服務(wù)端AIDL的interface對象本身,就是Stub论衍,否則返回Stub.proxy
proxy獲取換過去的Ibinder mremote
- 生成_data _reply數(shù)據(jù)流data.writeInterfaceToken(DESCRIPOR)
- 調(diào)用mremote.transact傳給服務(wù)端并請求服務(wù)端調(diào)用指定方法瑞佩。調(diào)用的是Stub中的實現(xiàn)方法。
- 接收reply數(shù)據(jù)流
服務(wù)端分析
1獲取客戶端傳過來數(shù)據(jù)坯台,根據(jù)ID執(zhí)行響應(yīng)操作
2傳過來數(shù)據(jù)data取出來炬丸,調(diào)用本地方法。data.enforceInterface(DESCRIPTOP)
3回傳數(shù)據(jù)寫入reply
服務(wù)端調(diào)用客戶端方法
提供一個AIDL的客戶端方法的接口蜒蕾,因為AIDL中無法使用普通接口
在客戶端中對方法進行具體實現(xiàn)
Binder連接池
- 為連接池創(chuàng)建queryBinder接口
- 為連接池創(chuàng)建遠程service稠炬,并實現(xiàn)queryBinder,返回需要具體的繼承Stub的Binder對象
使用
- 連接service咪啡,獲取Binderpoor
- 獲得連接池
- 通過queryBinder獲取Binder
注意事項
- onTransact返回false首启,客戶端的請求會失效。
- 客戶端線程會被掛起直至服務(wù)端進程返回數(shù)據(jù)撤摸,所以耗時方法不應(yīng)在UI線程執(zhí)行毅桃。
- 服務(wù)端的Binder 方法在Binder線程池中褒纲,所以應(yīng)采用同步方式。
- Binder意外死亡钥飞,需要重新連接服務(wù)莺掠,兩種方法,第一種給Binder設(shè)置死亡代理读宙,linkToDeath(DeathRecipient{binderDied{unlinkToDeath}})設(shè)置死亡代理汁蝶,死亡會回調(diào)客戶端Binder線程池中binderDied方法。第二種方法论悴,在onServiceDisconnected重連掖棉,在客戶端中UI線程中被回調(diào)。另外可以設(shè)置isBinderAlive檢查Binder是否死亡
- CopyOnWriteArrayList支持并發(fā)讀寫
- RemoteCallbackList 系統(tǒng)專門提供用于刪除跨進程listener接口 使用原因 多次跨進程傳輸客戶端的同一個對象會在服務(wù)端生成不同對象膀估,但新生成對象底層Binder對象是同一個
- 客戶端調(diào)用遠程服務(wù)的方法幔亥,被調(diào)用的方法運行在服務(wù)端的Binder線程池中,Binder線程池可以執(zhí)行大量耗時工作察纯,如果某個遠程方法是耗時的帕棉,避免在UI線程中調(diào)用。遠程服務(wù)端調(diào)用客戶端中方法饼记,被調(diào)用方法運行在客戶端Binder線程池中香伴,不能訪問UI內(nèi)容,如果要訪問客戶端UI具则,需要使用Handler切換到UI線程
- 在AIDL中使用權(quán)限驗證功能即纲,1在onBind中進行驗證,使用permission博肋,返回null2在服務(wù)端onTransact方法中返回false,可以通過permission或UidPid驗證
IPC方式
1使用Bundle低斋,只能放入序列化數(shù)據(jù)
2使用文件共享,避免數(shù)據(jù)同步匪凡,妥善處理并發(fā)讀寫膊畴。不建議SharedPreferences,緩存在內(nèi)存中病游,多進程模式下讀寫不可靠唇跨,會丟失數(shù)據(jù)。
3Messenger
4AIDL
5ContentProvider
底層Binder
通過ContentProvider跨進程通信
- ContentProvider六個方法衬衬,onCreat運行在主線程买猖,其他getTypeCRUD運行在Binder線程池中,每次的線程都不一樣
4Socket
流勢套接字Tcp 用戶數(shù)據(jù)報套接字UDP