還沒弄懂四大組件?帶你全面解析BroadcastReceiver

嗨,你終於來啦 ~ 等你很久啦~ 喜歡的小夥伴歡迎關注,我會按期分享Android知識點及解析,還會不斷更新的BATJ面試專題,歡迎你們前來探討交流,若有好的文章也歡迎投稿。javascript

前言

以前有些小夥伴私信我,想讓我說說關於Android四大組件的問題,這段時間工做上比較忙,因此就擱置了下來~今天項目終於告一段落,因此我決定從這篇起分別說一下關於四大組件的深刻知識~java

你們都知道BroadcastReceiver(廣播接收器),屬於 Android 四大組件之一在 Android 開發中,BroadcastReceiver 的應用場景很是多,因此今天第一篇,我將詳細講解關於BroadcastReceiver的一切相關知識。android

目錄

1. 定義

即 廣播,是一個全局的監聽器,屬於Android四大組件之一面試

Android 廣播分爲兩個角色:廣播發送者、廣播接收者設計模式

2. 做用

監聽 / 接收 應用 App 發出的廣播消息,並 作出響應安全

3. 應用場景

  • Android不一樣組件間的通訊(含 :應用內 / 不一樣應用之間)
  • 多線程通訊
  • Android 系統在特定狀況下的通訊

如:電話呼入時、網絡可用時網絡

4. 實現原理

4.1 採用的模型

  • Android中的廣播使用了設計模式中的觀察者模式:基於消息的發佈 / 訂閱事件模型

所以,Android將廣播的發送者 和 接收者 解耦,使得系統方便集成,更易擴展多線程

4.2 模型講解

  • 模型中有3個角色:app

    1. 消息訂閱者(廣播接收者)
    2. 消息發佈者(廣播發布者)
    3. 消息中心(AMS,即Activity Manager Service
  • 示意圖 & 原理以下ide

示意圖

5. 使用流程

  • 使用流程以下:
示意圖
  • 下面,我將一步步介紹如何使用BroadcastReceiver

即上圖中的 開發者手動完成部分

5.1 自定義廣播接收者BroadcastReceiver

  • 繼承BroadcastReceivre基類
  • 必須複寫抽象方法onReceive()方法
  1. 廣播接收器接收到相應廣播後,會自動回調 onReceive() 方法
  2. 通常狀況下,onReceive方法會涉及 與 其餘組件之間的交互,如發送Notification、啓動Service
  3. 默認狀況下,廣播接收器運行在 UI 線程,所以,onReceive()方法不能執行耗時操做,不然將致使ANR
  • 代碼範例
    mBroadcastReceiver.java
// 繼承BroadcastReceivre基類
public class mBroadcastReceiver extends BroadcastReceiver {

  // 複寫onReceive()方法
  // 接收到廣播後,則自動調用該方法
  @Override
  public void onReceive(Context context, Intent intent) {
   //寫入接收廣播後的操做
    }
}

複製代碼

5.2 廣播接收器註冊

註冊的方式分爲兩種:靜態註冊、動態註冊

5.2.1 靜態註冊

  • 註冊方式:在AndroidManifest.xml裏經過<receive>標籤聲明
  • 屬性說明:
<receiver 
    android:enabled=["true" | "false"]
//此broadcastReceiver可否接收其餘App的發出的廣播
//默認值是由receiver中有無intent-filter決定的:若是有intent-filter,默認值爲true,不然爲false
    android:exported=["true" | "false"]
    android:icon="drawable resource"
    android:label="string resource"
//繼承BroadcastReceiver子類的類名
    android:name=".mBroadcastReceiver"
//具備相應權限的廣播發送者發送的廣播才能被此BroadcastReceiver所接收;
    android:permission="string"
//BroadcastReceiver運行所處的進程
//默認爲app的進程,能夠指定獨立的進程
//注:Android四大基本組件均可以經過此屬性指定本身的獨立進程
    android:process="string" >

//用於指定此廣播接收器將接收的廣播類型
//本示例中給出的是用於接收網絡狀態改變時發出的廣播
 <intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> </intent-filter> </receiver>
複製代碼
  • 註冊示例
<receiver 
    //此廣播接收者類是mBroadcastReceiver
    android:name=".mBroadcastReceiver" >
    //用於接收網絡狀態改變時發出的廣播
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> </intent-filter> </receiver>
複製代碼

當此 App首次啓動時,系統會自動實例化mBroadcastReceiver類,並註冊到系統中。

5.2.2 動態註冊

  • 註冊方式:在代碼中調用Context.registerReceiver()方法

  • 具體代碼以下:

// 選擇在Activity生命週期方法中的onResume()中註冊
@Override
  protected void onResume(){
      super.onResume();

    // 1. 實例化BroadcastReceiver子類 & IntentFilter
     mBroadcastReceiver mBroadcastReceiver = new mBroadcastReceiver();
     IntentFilter intentFilter = new IntentFilter();

    // 2. 設置接收廣播的類型
    intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);

    // 3. 動態註冊:調用Context的registerReceiver()方法
     registerReceiver(mBroadcastReceiver, intentFilter);
 }


// 註冊廣播後,要在相應位置記得銷燬廣播
// 即在onPause() 中unregisterReceiver(mBroadcastReceiver)
// 當此Activity實例化時,會動態將MyBroadcastReceiver註冊到系統中
// 當此Activity銷燬時,動態註冊的MyBroadcastReceiver將再也不接收到相應的廣播。
 @Override
 protected void onPause() {
     super.onPause();
      //銷燬在onResume()方法中的廣播
     unregisterReceiver(mBroadcastReceiver);
     }
}
複製代碼

特別注意

  • 動態廣播最好在ActivityonResume()註冊、onPause()註銷。
  • 緣由:
    1. 對於動態廣播,有註冊就必然得有註銷,不然會致使內存泄露

重複註冊、重複註銷也不容許

  1. Activity生命週期以下:
Activity生命週期

Activity生命週期的方法是成對出現的:

  • onCreate() & onDestory()
  • onStart() & onStop()
  • onResume() & onPause()

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

  1. 不在onCreate() & onDestory() 或 onStart() & onStop()註冊、註銷是由於:
    當系統由於內存不足(優先級更高的應用須要內存,請看上圖紅框)要回收Activity佔用的資源時,Activity在執行完onPause()方法後就會被銷燬,有些生命週期方法onStop(),onDestory()就不會執行。當再回到此Activity時,是從onCreate方法開始執行。
  2. 假設咱們將廣播的註銷放在onStop(),onDestory()方法裏的話,有可能在Activity被銷燬後還未執行onStop(),onDestory()方法,即廣播仍還未註銷,從而致使內存泄露。
  3. 可是,onPause()必定會被執行,從而保證了廣播在App死亡前必定會被註銷,從而防止內存泄露。

5.2.3 兩種註冊方式的區別

示意圖

5.3 廣播發送者向AMS發送廣播

5.3.1 廣播的發送
  • 廣播 是 用」意圖(Intent)「標識
  • 定義廣播的本質 = 定義廣播所具有的「意圖(Intent)」
  • 廣播發送 = 廣播發送者 將此廣播的「意圖(Intent)」經過sendBroadcast()方法發送出去
5.3.2 廣播的類型

廣播的類型主要分爲5類:

  • 普通廣播(Normal Broadcast
  • 系統廣播(System Broadcast
  • 有序廣播(Ordered Broadcast
  • 粘性廣播(Sticky Broadcast
  • App應用內廣播(Local Broadcast

具體說明以下:
1. 普通廣播(Normal Broadcast)
即 開發者自身定義 intent的廣播(最經常使用)。發送廣播使用以下:

Intent intent = new Intent();
//對應BroadcastReceiver中intentFilter的action
intent.setAction(BROADCAST_ACTION);
//發送廣播
sendBroadcast(intent);
複製代碼
  • 若被註冊了的廣播接收者中註冊時intentFilteraction與上述匹配,則會接收此廣播(即進行回調onReceive())。以下mBroadcastReceiver則會接收上述廣播
<receiver 
    //此廣播接收者類是mBroadcastReceiver
    android:name=".mBroadcastReceiver" >
    //用於接收網絡狀態改變時發出的廣播
    <intent-filter>
        <action android:name="BROADCAST_ACTION" /> </intent-filter> </receiver>
複製代碼
  • 若發送廣播有相應權限,那麼廣播接收者也須要相應權限

2. 系統廣播(System Broadcast)

  • Android中內置了多個系統廣播:只要涉及到手機的基本操做(如開機、網絡狀態變化、拍照等等),都會發出相應的廣播
  • 每一個廣播都有特定的Intent - Filter(包括具體的action),Android系統廣播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卡) Intent.ACTION_MEDIA_CHECKING
成功安裝APK Intent.ACTION_PACKAGE_ADDED
成功刪除APK Intent.ACTION_PACKAGE_REMOVED
重啓設備 Intent.ACTION_REBOOT
屏幕被關閉 Intent.ACTION_SCREEN_OFF
屏幕被打開 Intent.ACTION_SCREEN_ON
關閉系統時 Intent.ACTION_SHUTDOWN
重啓設備 Intent.ACTION_REBOOT

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

3. 有序廣播(Ordered Broadcast)

  • 定義
    發送出去的廣播被廣播接收者按照前後順序接收

有序是針對廣播接收者而言的

  • 廣播接受者接收廣播的順序規則(同時面向靜態和動態註冊的廣播接受者)

    1. 按照Priority屬性值從大-小排序;
    2. Priority屬性相同者,動態註冊的廣播優先;
  • 特色

    1. 接收廣播按順序接收
    2. 先接收的廣播接收者能夠對廣播進行截斷,即後接收的廣播接收者再也不接收到此廣播;
    3. 先接收的廣播接收者能夠對廣播進行修改,那麼後接收的廣播接收者將接收到被修改後的廣播
  • 具體使用
    有序廣播的使用過程與普通廣播很是相似,差別僅在於廣播的發送方式:

sendOrderedBroadcast(intent);
複製代碼

4. App應用內廣播(Local Broadcast)

  • 背景
    Android中的廣播能夠跨App直接通訊(exported對於有intent-filter狀況下默認值爲true)

  • 衝突
    可能出現的問題:

    • 其餘App針對性發出與當前App intent-filter相匹配的廣播,由此致使當前App不斷接收廣播並處理;
    • 其餘App註冊與當前App一致的intent-filter用於接收廣播,獲取廣播具體信息;
      即會出現安全性 & 效率性的問題。
  • 解決方案
    使用App應用內廣播(Local Broadcast)

  1. App應用內廣播可理解爲一種局部廣播,廣播的發送者和接收者都同屬於一個App。
  2. 相比於全局廣播(普通廣播),App應用內廣播優點體如今:安全性高 & 效率高
  • 具體使用1 - 將全局廣播設置成局部廣播

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

    經過intent.setPackage(packageName)指定報名

  • 具體使用2 - 使用封裝好的LocalBroadcastManager類
    使用方式上與全局廣播幾乎相同,只是註冊/取消註冊廣播接收器和發送廣播時將參數的context變成了LocalBroadcastManager的單一實例

注:對於LocalBroadcastManager方式發送的應用內廣播,只能經過LocalBroadcastManager動態註冊,不能靜態註冊

//註冊應用內廣播接收器
//步驟1:實例化BroadcastReceiver子類 & IntentFilter mBroadcastReceiver 
mBroadcastReceiver = new mBroadcastReceiver(); 
IntentFilter intentFilter = new IntentFilter(); 

//步驟2:實例化LocalBroadcastManager的實例
localBroadcastManager = LocalBroadcastManager.getInstance(this);

//步驟3:設置接收廣播的類型 
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);

//步驟4:調用LocalBroadcastManager單一實例的registerReceiver()方法進行動態註冊 
localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);

//取消註冊應用內廣播接收器
localBroadcastManager.unregisterReceiver(mBroadcastReceiver);

//發送應用內廣播
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION);
localBroadcastManager.sendBroadcast(intent);

複製代碼

5. 粘性廣播(Sticky Broadcast)
因爲在Android5.0 & API 21中已經失效,因此不建議使用,在這裏也不做過多的總結。

6. 特別注意

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

  • 對於靜態註冊(全局+應用內廣播),回調onReceive(context, intent)中的context返回值是:ReceiverRestrictedContext;
  • 對於全局廣播的動態註冊,回調onReceive(context, intent)中的context返回值是:Activity Context;
  • 對於應用內廣播的動態註冊(LocalBroadcastManager方式),回調onReceive(context, intent)中的context返回值是:Application Context。
  • 對於應用內廣播的動態註冊(非LocalBroadcastManager方式),回調onReceive(context, intent)中的context返回值是:Activity Context;

7. 總結

  • 本文主要介紹了Android中四大組件的BroadcastReceiver的全部知識,以爲文章不錯的喜歡的小夥伴能夠關注加分享,也歡迎你們前來探討交流。
相關文章
相關標籤/搜索