Android學習(三)——四大組件之BroadcastReceiver

BroadcastReceiver基礎使用

BroadCastReceiver簡介

BroadCastReceiver,即廣播接收器,運行在主線程用於監聽全局廣播

作爲Android四大組件之一,BroadCastReceiver起着重要的作用,一般用於接收推送,跨進程通信等不方便直接通信操作的地方或者監聽某些不定時完成的事務

廣播主要有兩種:有序廣播和無序廣播

  • 無序廣播:所有跟廣播的intent匹配的廣播接收者都可以收到該廣播,並且是沒有先後順序,效率搞,但是接收者不能傳遞也不能截斷廣播
  • 有序廣播:所有跟廣播的intent匹配的廣播接收者都可以收到該廣播,但是會按照廣播接收者的優先級來決定接收的先後順序,每一個接收者都有權修改並將修改的廣播傳給下一個接收者,也可以攔截。

BroadcastReceiver的實現原理

之前使用的時候並沒有在意它的實現原理,只是知道這麼用

廣播的設計模式是標準的觀察者模式,對於廣播而言最重要的是Android的AMS(ActivityManagerService),消息發佈者在AMS中註冊,通過Binder機制發送廣播,AMS在註冊列表尋找到合適的接收者,將廣播發送到接收者的消息循環隊列(BroadcastQueue)中,廣播接收者通過消息循環拿到廣播並調用回調方法onReceive();

Created with Raphaël 2.1.0發佈者發佈者AMSAMS接收者接收者註冊註冊發廣播尋找合適的接收者找到合適的接收者發送廣播到接收者消息隊列消息循環拿到該廣播

這觀察者模式好屌,嚇得我趕緊去看這個設計模式怎麼用了

定義一個BroadcastReceiver

定義個廣播接收器還是挺簡單的

  • 首先我們要新建一個類(至於是單獨文件的類還是內部類這個要看使用場景,不過都可以的)並繼承BroadcastReceiver類
  • 重寫裏面的onReceive方法
public class MyBroadcastReceiver extends BroadcastReceiver {

 @Override
 public void onReceive(Context context, Intent intent) {
     //接收廣播後的操作
     } 
}

BroadcastReceiver的註冊

作爲Android四大組件之一,你Activity和Service都在Manifest裏面註冊了,我BroadcastReceiver要是不註冊,我不要面子噠?

BroadcastReceiver的註冊分爲兩種:靜態註冊和動態註冊

靜態註冊

靜態註冊實在AndroidManifest裏面添加 <receiver>標籤

<receiver
     //是否能夠實例化這個接收器可以爲true,若爲false則不能被實例化
    android:enabled=["true" | "false"]
    //此接收器能否接受其他APP發出的廣播,如果內部包含intent-filter標籤則默認爲true,否則默認false
    android:exported=["true" | "false"]
    //一個代表廣播接收器的圖標,不定義默認爲application標籤的icon
    android:icon="drawable resource"
    android:label="string resource"//標籤
    //這個屬性一般爲廣播接收器實現類的類名(全名,要有包名的那種;或者直接.CLASSNAME,這樣系統會默認吧manifest的包名加到前面)
    android:name="string"
    //這個屬性用於定義把消息發送給該廣播接收器的廣播器所必須要有的權限。
    android:permission="string"
    這個屬性用於設置該廣播接收器應該運行在那個進程中的進程名。
    android:process="string">
    <intent-filter>
        //這裏的action,就是我們發送的廣播的事件名
        <action android:name="actionName" />
    </intent-filter>
</receiver>

當此app首次啓動時,系統會自動實例化該廣播接收器的實現類,並註冊到系統中。

動態註冊

是指不在Manifest裏面添加標籤,而是在代碼中動態調用Context的registerReceiver()方法。

private MyBroadcastReceiver mBroadcastReceiver;

@Override 
protected void onResume(){ 
    super.onResume(); 
    mBroadcastReceiver = new MyBroadcastReceiver ();
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE); 

    registerReceiver(mBroadcastReceiver, intentFilter); 
} 

@Override 
protected void onPause() { 
    super.onPause(); 
    unregisterReceiver(mBroadcastReceiver); 
} 

動態廣播由於需要註銷防止內存泄漏,所以推薦在onResume方法中註冊,onPause方法中註銷,同時重複註冊,重複註銷也不允許

在onResume()註冊、onPause()註銷是因爲onPause()在App死亡前一定會被執行,從而保證廣播在App死亡前一定會被註銷,從而防止內存泄露。

靜態註冊與動態註冊的區別

  • 兩個方式的註冊方式不同
    • 靜態:在manifest中註冊
    • 動態:在代碼中註冊
  • 兩個方式的監聽範圍不同
    • 靜態:會時刻監聽廣播
    • 動態:在特定時刻監聽廣播
  • 兩個方式的生命週期不同
    • 靜態:常駐後臺,不受任何組件生命週期影響,耗電多佔內存大
    • 動態:部常駐,靈活,跟隨組件的生命週期變化,一旦移除就不會接受廣播

發送廣播

廣播是通過sendBroadcast()方法,以Intent爲傳輸工具進行發送的

廣播主要分爲5類:

  • 普通廣播
  • 系統廣播
  • 有序廣播
  • 粘性廣播
  • 應用內廣播

普通廣播

    Intent intent = new Intent();
    intent.setAction(NROMAL_ACTION);
    sendBroadcast(intent);

NROMAL_ACTION 就是你之前註冊的廣播事件

系統廣播

這個並不是手動發送的,而是系統默認發送的,我們只需要監聽就好

具體操作 action名稱
監聽網絡變化 android.net.conn.CONNECTIVITY_CHANGE
關閉或打開飛行模式 Intent.ACTION_AIRPLANE_MODE_CHANGED
充電時或電量發生變化 Intent.ACTION_BATTERY_CHANGED
電池電量低 Intent.ACTION_BATTERY_LOW
電池電量充足(即從電量低變化到飽滿時會發出廣播 Intent.ACTION_BATTERY_OKAY
系統啓動完成後(僅廣播一次) Intent.ACTION_BOOT_COMPLETED
按下照相時的拍照按鍵(硬件按鍵)時 Intent.ACTION_CAMERA_BUTTON
屏幕鎖屏 Intent.ACTION_CLOSE_SYSTEM_DIALOGS
設備當前設置被改變時(界面語言、設備方向等) Intent.ACTION_CONFIGURATION_CHANGED
插入耳機時 Intent.ACTION_HEADSET_PLUG
未正確移除SD卡但已取出來時(正確移除方法:設置–SD卡和設備內存–卸載SD卡) Intent.ACTION_MEDIA_BAD_REMOVAL
插入外部儲存裝置(如SD卡) tent.ACTION_MEDIA_CHECKING
成功安裝APK Intent.ACTION_PACKAGE_REMOVED
成功刪除APK Intent.ACTION_BATTERY_CHANGED
重啓設備 Intent.ACTION_REBOOT
屏幕被關閉 Intent.ACTION_SCREEN_OFF
屏幕被打開 Intent.ACTION_SCREEN_ON
關閉系統時 Intent.ACTION_SHUTDOWN
重啓設備 Intent.ACTION_REBOOT

當使用系統廣播時,只需要在註冊廣播接收者時定義相關的action即可,並不需要手動發送廣播,當系統有相關操作時會自動進行系統廣播

有序廣播

發送出去的廣播被廣播接收者按照先後順序接收,這裏的有序是針對接受者的

  • 廣播接收的順序規則
    • 按照Priority屬性的值,從大到小排序
    • Priority屬性的值相同時,動態註冊的廣播優先

使用方式

sendOrderedBroadcast(intent);

應用內廣播

  • 註冊廣播時將exported屬性設置爲false,使得非本App內部發出的此廣播不被接收;
  • 發送廣播時指定該廣播接收器所在的包名,此廣播將只會發送到此包中的App內與之相匹配的有效廣播接收器中,通過intent.setPackage(packageName)指定報名
  • 在廣播發送和接收時,增設相應權限permission,用於權限驗證;

    除了以上幾種方式,也可以使用LocalBroadcastManager

  • 使用方式上與全局廣播幾乎相同,只是註冊/取消註冊廣播接收器和發送廣播時將參數的context變成了LocalBroadcastManager的單一實例,對於LocalBroadcastManager方式發送的應用內廣播,只能通過LocalBroadcastManager動態註冊,不能靜態註冊

    //註冊應用內廣播接收器 
    //步驟1:實例化BroadcastReceiver子類 & IntentFilter 
    MyBroadcastReceiver mBroadcastReceiver = new MyBroadcastReceiver ();
    IntentFilter intentFilter = new IntentFilter();
    localBroadcastManager = LocalBroadcastManager.getInstance(this); 
    //步驟3:設置接收廣播的類型 
    intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE); 
    //步驟4:調用LocalBroadcastManager單一實例的registerReceiver()方法進行動態註冊 
    localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter); 
    //取消註冊應用內廣播接收器 
    localBroadcastManager.unregisterReceiver(mBroadcastReceiver);
     //發送應用內廣播 
    intent.setAction(BROADCAST_ACTION);
    localBroadcastManager.sendBroadcast(intent);

關於onReceive(Context context,Intent intent)方法

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

  1. 對於靜態註冊(全局+應用內廣播),回調onReceive(context, intent)中的context返回值是:ReceiverRestrictedContext;
  2. 對於全局廣播的動態註冊,回調onReceive(context, intent)中的context返回值是:Activity Context;
  3. 對於應用內廣播的動態註冊(LocalBroadcastManager方式),回調onReceive(context, intent)中的context返回值是:Application Context。
  4. 對於應用內廣播的動態註冊(非LocalBroadcastManager方式),回調onReceive(context, intent)中的context返回值是:Activity Context;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章