廣播(Broadcast)機制用於進程/線程間通信,廣播分為廣播發送和廣播接收兩個過程,其中廣播接收者BroadcastReceiver便是Android四大組件之壹。
BroadcastReceiver分為兩類:
從廣播發送方式可分為三類:
廣播在系統中以BroadcastRecord對象來記錄, 該對象有幾個時間相關的成員變量.
廣播註冊,對於應用開發來說,往往是在Activity/Service中調用 registerReceiver() 方法,而Activity或Service都間接繼承於Context抽象類,真正幹活是交給ContextImpl類。另外調用getOuterContext()可獲取最外層的調用者Activity或Service。
[ContextImpl.java]
其中broadcastPermission擁有廣播的權限控制,scheduler用於指定接收到廣播時onRecive執行線程,當scheduler=null則默認代表在主線程中執行,這也是最常見的用法
[ContextImpl.java]
ActivityManagerNative.getDefault()返回的是ActivityManagerProxy對象,簡稱AMP.
該方法中參數有mMainThread.getApplicationThread()返回的是ApplicationThread,這是Binder的Bn端,用於system_server進程與該進程的通信。
[-> LoadedApk.java]
不妨令 以BroadcastReceiver(廣播接收者)為key,LoadedApk.ReceiverDispatcher(分發者)為value的ArrayMap 記為 A 。此處 mReceivers 是壹個以 Context 為key,以 A 為value的ArrayMap。對於ReceiverDispatcher(廣播分發者),當不存在時則創建壹個。
此處mActivityThread便是前面傳遞過來的當前主線程的Handler.
ReceiverDispatcher(廣播分發者)有壹個內部類 InnerReceiver ,該類繼承於 IIntentReceiver.Stub 。顯然,這是壹個Binder服務端,廣播分發者通過rd.getIIntentReceiver()可獲取該Binder服務端對象 InnerReceiver ,用於Binder IPC通信。
[-> ActivityManagerNative.java]
這裏有兩個Binder服務端對象 caller 和 receiver ,都代表執行註冊廣播動作所在的進程. AMP通過Binder驅動將這些信息發送給system_server進程中的AMS對象,接下來進入AMS.registerReceiver。
[-> ActivityManagerService.java]
其中 mRegisteredReceivers 記錄著所有已註冊的廣播,以receiver IBinder為key, ReceiverList為value為HashMap。
在BroadcastQueue中有兩個廣播隊列mParallelBroadcasts,mOrderedBroadcasts,數據類型都為ArrayList<broadcastrecord style="box-sizing: border-box;">:</broadcastrecord>
mLruProcesses數據類型為 ArrayList<ProcessRecord> ,而ProcessRecord對象有壹個IApplicationThread字段,根據該字段查找出滿足條件的ProcessRecord對象。
該方法用於匹配發起的Intent數據是否匹配成功,匹配項***有4項action, type, data, category,任何壹項匹配不成功都會失敗。
broadcastQueueForIntent(Intent intent)通過判斷intent.getFlags()是否包含FLAG_RECEIVER_FOREGROUND 來決定是前臺或後臺廣播,進而返回相應的廣播隊列mFgBroadcastQueue或者mBgBroadcastQueue。
註冊廣播:
另外,當註冊的是Sticky廣播:
廣播註冊完, 另壹個操作便是在廣播發送過程.
發送廣播是在Activity或Service中調用 sendBroadcast() 方法,而Activity或Service都間接繼承於Context抽象類,真正幹活是交給ContextImpl類。
[ContextImpl.java]
[-> ActivityManagerNative.java]
[-> ActivityManagerService.java]
broadcastIntent()方法有兩個布爾參數serialized和sticky來***同決定是普通廣播,有序廣播,還是Sticky廣播,參數如下:
broadcastIntentLocked方法比較長,這裏劃分為8個部分來分別說明。
這個過程最重要的工作是:
BroadcastReceiver還有其他flag,位於Intent.java常量:
主要功能:
這個過主要處於系統相關的10類廣播,這裏不就展開講解了.
這個過程主要是將sticky廣播增加到list,並放入mStickyBroadcasts裏面。
其他說明:
AMS.collectReceiverComponents :
廣播隊列中有壹個成員變量 mParallelBroadcasts ,類型為ArrayList<broadcastrecord style="box-sizing: border-box;">,記錄著所有的並行廣播。</broadcastrecord>
動態註冊的registeredReceivers,全部合並都receivers,再統壹按串行方式處理。
廣播隊列中有壹個成員變量 mOrderedBroadcasts ,類型為ArrayList<broadcastrecord style="box-sizing: border-box;">,記錄著所有的有序廣播。</broadcastrecord>
發送廣播過程:
處理方式:
可見不管哪種廣播方式,都是通過broadcastQueueForIntent()來根據intent的flag來判斷前臺隊列或者後臺隊列,然後再調用對應廣播隊列的scheduleBroadcastsLocked方法來處理廣播;
在發送廣播過程中會執行 scheduleBroadcastsLocked 方法來處理相關的廣播
[-> BroadcastQueue.java]
在BroadcastQueue對象創建時,mHandler=new BroadcastHandler(handler.getLooper());那麽此處交由mHandler的handleMessage來處理:
由此可見BroadcastHandler采用的是”ActivityManager”線程的Looper
[-> BroadcastQueue.java]
此處mService為AMS,整個流程還是比較長的,全程持有AMS鎖,所以廣播效率低的情況下,直接會嚴重影響這個手機的性能與流暢度,這裏應該考慮細化同步鎖的粒度。