分享一些 Broadcast 使用技巧

簡介

Broadcast(廣播) 是 Android 的四大組件之一,用於進程/線程間通訊。java

廣播最大的特色就是發送方並不關心接收方是否接到數據,也不關心接收方是如何處理數據的,它只負責「說」而無論你「聽不聽」。android

廣播能夠來之系統,例如,Android 系統在發生各類系統事件時發送廣播(系統啓動或者設備開始充電時)。git

也能夠來自於其餘應用程序,例如,應用程序也能夠發送自定義廣播,來通知其餘應用程序接受他們可能感興趣的內容(更新數據)。github

廣播的分類

按發送方式分類

  • 標準廣播

是一種「徹底異步執行」的廣播,沒有任何前後順序,全部的廣播接收器幾乎同一時刻接收到這條廣播消息,效率高,沒法被截斷。安全

  • 有序廣播

是一種「同步執行」的廣播,有前後順序,同一時刻只有一個接收器能夠接收這個廣播消息,優先級高的廣播接收器能夠先收到廣播消息,而且前面的廣播接收器還能夠截斷正在傳遞的廣播,這樣後面的廣播接收器就沒法接收廣播消息了。網絡

按註冊方式分類

  • 靜態廣播

無論應用程序是否處於活動狀態,都會進行監聽。每次觸發都會創建新的 Receiver 對象。app

  • 動態廣播

在代碼中進行註冊,注意動態註冊的廣播必定要取消註冊才行,一般是在 onDestroy() 方法中調用 unregisterReceiver() 方法來實現。異步

從開始建立直到其被解除註冊會使用同一個 Receiver,不管這個廣播被觸發幾回。ide

按定義方式分類

  • 系統廣播

Android 系統中內置了多個系統廣播,每一個系統廣播都具備特定的 IntentFilter,其中主要包括具體的 Action,系統廣播發出後,將被相應的 BroadcastReceiver 接收。系統廣播在系統內部當特定事件發生時,由系統自動發出。學習

  • 自定義廣播

由應用程序開發者本身定義的廣播。

按範圍方式分類

  • 全局廣播

發出的廣播能夠被其餘任意的應用程序接收,或者能夠接收來自其餘任意應用程序的廣播。

  • 本地廣播

只能在應用程序的內部進行傳遞的廣播,廣播接收器也只能接收內部的廣播,不能接受其餘應用程序的廣播。

廣播的使用

建立廣播接收器

使用廣播咱們須要先建立 BroadcastReceiver(廣播接收器) ,直接繼承 BroadcastReceiver 建立子類並實現父類的 onReceive() 方法便可,以下示例代碼。

public class MyReceiver extends BroadcastReceiver {
  // 自定義 action
  private static final String ACTION = "com.jeanboy.broadcast.MyReceiverFilter";
  
  @Override
  public void onReceive(Context context, Intent intent) {
    //TODO: 接收到廣播進行處理
  }
}
複製代碼

靜態廣播

在使用廣播時還須要在 AndroidMainfest 文件中定義,也就是註冊靜態廣播。

<receiver android:name=".ui.broadcast.MyReceiver" android:enabled="true" android:exported="true">
    <intent-filter>
        <!-- 例如:接收系統開機廣播 -->
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <!-- 例如:接收自定義的廣播 -->
        <action android:name="com.jeanboy.broadcast.MyReceiverFilter" />
    </intent-filter>
</receiver>
複製代碼

上面的 enabled 設置爲 true 意味着可以接受到廣播信息。exported 爲 true 意味着可以接收到外部 APK 發送的廣播信息。

動態廣播

使用動態廣播不須要在 AndroidMainfest 文件中定義,只需在代碼中註冊便可。

// 建立廣播
MyReceiver myReceiver = new MyReceiver();
// 建立 IntentFilter
IntentFilter intentFilter = new IntentFilter();
// 例如:添加系統廣播 action 接受網絡變化
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
// 例如:添加自定義的 action
intentFilter.addAction(MyReceiver.ACTION);
// 註冊廣播
registerReceiver(myReceiver, intentFilter);
// 註銷廣播
unregisterReceiver(myReceiver);
複製代碼

發送廣播

發送廣播比較簡單,不管靜態廣播仍是動態廣播,都是以下方式(系統廣播 Android 系統會自動發送,不在本文討論範圍)。

// 建立 Intent
Intent intent = new Intent();
// 例如:添加自定義的 action
intent.setAction(MyReceiver.ACTION);
// 發送廣播
sendBroadcast(intent);
複製代碼

Android 8.0 中的靜態廣播

因爲 Android 8.0 廢除大部分靜態廣播,對於代碼須要修改某些部分。

發送廣播部分須要設置 ComponetName

Intent intent = new Intent(MyReceiver.ACTION);
// ComponetName("自定義廣播的包名", "自定義廣播的路徑")
ComponentName component = new ComponentName("com.jeanboy.app.broadcast", "com.jeanboy.app.broadcast.MyReceiver");
intent.setComponent(component);
sendBroadcast(intent);
複製代碼

帶權限的廣播

使用廣播可能引起的安全問題:

  • 若是別的應用程序監聽咱們的廣播,那麼會形成咱們應用程序的數據泄露;
  • 若是別的應用程序冒充咱們的應用發送廣播,那麼就會頻繁的啓動咱們的廣播接收程序,形成咱們應用的混亂,甚至崩潰。

爲了不以上安全問題,Android 爲咱們提供了權限機制。

首先在註冊靜態廣播時能夠在 AndroidMainfest 文件中添加權限。

<manifest ...>
  <!-- 自定義一個本身的權限 -->
  <permission android:name="com.jeanboy.permissions.MY_BROADCAST"/>
  <!-- 使用自定義的權限 -->
  <uses-permission android:name="com.jeanboy.permissions.MY_BROADCAST"/>

  <application ...>
    <!-- 添加權限 -->
    <receiver android:name=".ui.broadcast.MyReceiver" android:permission="com.jeanboy.broadcast.MY_BROADCAST" android:enabled="true" android:exported="true">
      <intent-filter>
        <!-- 例如:接收自定義的廣播 -->
        <action android:name="com.jeanboy.broadcast.MyReceiverFilter" />
      </intent-filter>
    </receiver>
  </application>
</manifest>
複製代碼

而後在咱們發送廣播時,能夠爲它指定一個權限,只有具備該權限的應用才能接收到廣播,以下所示:

// 建立 Intent
Intent intent = new Intent();
// 例如:添加自定義的 action
intent.setAction(MyReceiver.ACTION);
// 發送廣播,添加權限
sendBroadcast(intent, "com.jeanboy.permissions.MY_BROADCAST");
複製代碼

本地廣播

上面介紹的 BroadcastReceiver 用於應用之間的傳遞消息,本質上它是跨進程的,還有可能被其餘應用攔截。

而 LocalBroadcast(本地廣播)用於應用內部傳遞消息,比 BroadcastReceiver 更加高效,它只在應用內部有效,不須要考慮安全問題。

本地廣播的建立仍然是繼承 BroadcastReceiver 建立子類,並實現父類的 onReceive() 方法。在註冊、發送、註銷廣播時使用 LocalBroadcastManager 來進行相關操做。

// 建立廣播
MyReceiver myReceiver = new MyReceiver();
// 建立 IntentFilter
IntentFilter intentFilter = new IntentFilter();
// 例如:添加自定義的 action
intentFilter.addAction(MyReceiver.ACTION);
// 註冊本地廣播
LocalBroadcastManager.getInstance(this)
                .registerReceiver(myReceiver, intentFilter);

// 發送廣播
Intent intent = new Intent(MyReceiver.ACTION));
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

// 註銷本地廣播
LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceiver);
複製代碼

參考資料

個人 Github

github.com/jeanboydev/…

個人公衆號

歡迎關注個人公衆號,分享各類技術乾貨,各類學習資料,職業發展和行業動態。

Android 波斯灣

技術交流羣

歡迎加入技術交流羣,來一塊兒交流學習。

QQ 技術交流羣

QQ 技術交流羣
相關文章
相關標籤/搜索