Android BrocastReceiver解析

簡介

BroadcastReceiver(廣播接收器)是Android四大組件之一,是一個用來響應系統範圍內的廣播組件,能夠從Android系統和其它app發送或接收廣播消息,相似於發佈 - 訂閱設計模式。其特色是異步的,廣播發送者不會關心有無接收者接收。可應用於不一樣組件之間的通訊、多線程通訊和系統在特定狀況下的通訊。android

原理


對於不一樣的廣播類型,以及不一樣的BroadcastReceiver註冊方式,具體實現上會有不一樣。但整體流程大體以下:設計模式

  1. 廣播接收者BroadcastReceiver經過Binder機制向AMS(Activity Manager Service)進行註冊;
  2. 廣播發送者經過Binder機制向AMS發送廣播;
  3. AMS查找符合相應條件(IntentFilter/Permission等)的BroadcastReceiver,將廣播發送到BroadcastReceiver(通常狀況下是Activity)相應的消息循環隊列中;
  4. 消息循環執行拿到此廣播,回調BroadcastReceiver中的onReceive()方法。安全

    類型

  • 普通廣播(Normal Broadcast)

普通廣播是徹底異步的,經過Context的sendBroadcast()方法來發送,消息傳遞效率比較高,但全部receivers(接收器)的執行順序不肯定。缺點是接收器不能將處理結果傳遞給下一個接收器,而且沒法在中途終止廣播。網絡

val intent = Intent()
intent.action = RECEIVE_TOKEN
sendBroadcast(intent)
  • 系統廣播(System Broadcast)

Android系統中內置了多個系統廣播,只要涉及到手機的基本操做,基本上都會發出相應的系統廣播。如:開機啓動,充電與電量變化,網絡狀態改變,拍照,屏幕關閉與開啓等。每一個系統廣播都具備特定的intent-filter,其中主要包括具體的action,系統廣播發出後,將被相應的BroadcastReceiver接收。多線程

  • 有序廣播(Ordered Broadcast)

「有序」是針對廣播接收者而言的,指的是發送出去的廣播被BroadcastReceiver按照前後循序接收,經過receiver的intent-filter中的android:priority屬性來設置優先級,優先級從-1000~1000,數越大,優先級越高;priority屬性相同者,動態註冊的廣播優先。其使用過程與普通廣播很是相似,差別僅在於廣播的發送方式經過Context.sendOrderedBroadcast()方法發送。app

  • App應用內廣播(Local Broadcast)

Android中的廣播能夠跨App直接通訊,可能會帶來消耗性能和容易引發安全性的問題,爲了解決這些問題,將全局廣播設置成局部廣播或者使用封裝好的LocalBroadcastManager(只能動態註冊)類。
設置局部廣播方式:異步

  • 註冊廣播時將exported屬性設置爲false
  • 增設相應權限permission,用於權限驗證
  • 指定該廣播接收器所在的包名

LocalBroadcastManager使用ide

//註冊廣播,在Activity.onResume註冊
val intentFilter = IntentFilter()
val broadcastReceiver = BroadcastReceiver()
intentFilter.addAction(RECEIVE_TOKEN)
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, intentFilter)
//發送廣播
val intent = Intent()
intent.action = RECEIVE_TOKEN
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
//取消廣播,在Activity.onPause取消
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver)

註冊

  • 靜態註冊

直接在Manifest.xml文件的 節點中配置,使用< receiver >標籤聲明,並在標籤內用 < intent-filter > 標籤設置過濾器,該註冊方式無論app是否處於活動狀態,都會進行監聽。 性能

<receiver android:name=".BroadcastReceiver" // 繼承BroadcastReceiver子類的類名
          android:enabled="boolean"  // 可否接收其餘App的發出的廣播
          android:exported="boolean" // 默認值是由receiver中有無intent-filter決定的:若是有intent-filter,默認值爲true,不然爲false
          android:icon="drawable resource" // 廣播icon
          android:label="string resource" // 廣播標籤
          android:permission="string" // 具備相應權限的廣播發送者發送的廣播才能被此BroadcastReceiver所接收
          android:process="string"> // 指定本身的獨立進程
    <intent-filter>
        <action android:name="com.fomin.demo.ACTION_RECEIVE_TOKEN"/>
    </intent-filter>
</receiver>

但須要注意的是,Android8.0系統對靜態廣播作了變動,具體可查看[https://blog.csdn.net/fomin_zhu/article/details/84454042]this

  • 動態註冊

直接在代碼在代碼中調用Context.registerReceiver()方法註冊和調用unregisterReceiver
取消註冊

override fun onResume() {
    super.onResume()
    //註冊廣播,在Activity.onResume註冊
    val intentFilter = IntentFilter()
    intentFilter.addAction(RECEIVE_TOKEN)
     LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, intentFilter)
}

override fun onPause() {
    super.onPause()
    //取消廣播,在Activity.onPause取消
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver)
}

動態廣播最好在Activity 的 onResume()註冊、onPause()註銷,是由於對於動態廣播,有註冊就必然得有註銷,不然會致使內存泄露;在onResume()註冊、onPause()註銷是由於onPause()在App死亡前必定會被執行,從而保證廣播在App死亡前必定會被註銷,從而防止內存泄露。

  • 二者區別
    1. 靜態註冊在Manifest.xml註冊,動態在代碼上調用
    2. 靜態是常駐的,不受生命週期影響,而且耗電和佔內存;而動態是使用才註冊,跟隨組件生命週期

注意

不一樣註冊方式的廣播接收器回調OnReceive()中的context返回值是不同的

  • 靜態註冊廣播,content是android.app.ReceiverRestrictedContext,此context非Activity類型,不可直接用來構造AlertDialog
  • 動態註冊廣播,傳入onReceive()方法裏的Context對象context其實就是調用sendBroadcast()的Activty對象;但LocalBroadcastManager方式返回的是Application Context
相關文章
相關標籤/搜索