Android BroadCastReceiver 簡明使用
日更 16 天
本文主要記錄以下三個知識點:
Android 中的 BroadcastReceiver 是什麼?
BroadcastReceiver 的分類
BroadcastReceiver 的使用
Android 中的 BroadcastReceiver
BroadcastReceiver
又叫 廣播 ,顧名思義它的作用就是用來發送通知,在Android 中可以理解為傳送訊息。在 Android 中廣播分為 標準廣播 、 有序廣播
標準廣播
它是一種完全非同步執行的廣播,在廣播發出之後,如果沒有被中斷,那麼所有的廣播消費者就會接收到這條廣播,而且是沒有順序的接收到。由於它的無序狀態,所以這種廣播是無法被中斷的,類似下圖:

image.png
有序廣播
它是一種同步執行的廣播。廣播生產者發出廣播之後,在同一個時刻只會有一個廣播消費者接收到這條廣播。這個廣播是有優先順序順序的,優先順序高的會優先收到訊息,在訊息處理完了之後才傳遞給下一個廣播消費者。由於它是有順序的傳送,所以可以在某個優先順序高的消費者接收到訊息後就不傳遞給下一個消費者,這就控制了廣播的中斷。

image.png
廣播的使用
在 Android 系統中內建了很多系統級別的廣播,我們可以在應用程式中通過監聽這些廣播來得到各種系統的狀態資訊。比如手機開機會發送一條廣播,系統電腦發生變化會發出一條廣播,時間和時區發生改變也會發出一條廣播。當然系統內建的廣播不可能滿足我們的需求,所以我們還可以自定義廣播。如果想要接收到這些廣播,那麼就需要廣播接收器來接受資訊。
- 系統廣播
- 自定義廣播
- 標準廣播
- 有序廣播
系統廣播-動態註冊監聽網路變化
這裡講到了廣播的註冊方式,廣播的註冊方式分為 動態和靜態註冊兩種。
動態註冊是指在程式碼中根據頁面是否要接受訊息來動態註冊廣播(記得有註冊就有登出~)。
靜態註冊是指在 AndroidManifest.xml
檔案中直接註冊。
兩種註冊方式的區別:
-
靜態註冊的方式可以保證在應用程式安裝之後,
BroadcastReceiver
會一直存在,通常用於監聽系統狀態的改變,比如說手機的電量,wifi
狀態,等等。 -
動態註冊顧名思義相對靜態註冊要靈活的多,這樣註冊的
BroadcastReceiver
通常用於更新UI
的狀態。在頁面關閉時可關閉廣播,或者在不需要接受廣播的時候關閉(注意記憶體洩露)。
動態註冊實現網路狀態監聽的程式碼如下:
public class AActivity extends AppCompatActivity { private NetworkChangeReceiver mNetworkChangeReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_a); // 動態註冊網路監聽廣播 IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); mNetworkChangeReceiver = new NetworkChangeReceiver(); registerReceiver(mNetworkChangeReceiver,intentFilter); } @Override protected void onDestroy() { super.onDestroy(); // 動態登出網路監聽廣播 unregisterReceiver(mNetworkChangeReceiver); } // 這裡比較簡單就做內部類寫了,真實情況最好還是單獨做一個類來維護 class NetworkChangeReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { ConnectivityManager service = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); if (service != null){ // 需要在 androidmanifest.xml 中新增許可權 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> NetworkInfo activeNetworkInfo = service.getActiveNetworkInfo(); if (activeNetworkInfo != null && activeNetworkInfo.isAvailable()){ Toast.makeText(context, "有網", Toast.LENGTH_SHORT).show(); }else { Toast.makeText(context, "無網", Toast.LENGTH_SHORT).show(); } } } } }
再來一個系統廣播的使用例子, 靜態註冊實現開機啟動
- 定義一個廣播接收者
public class BootCompleteReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "開機啟動完成", Toast.LENGTH_SHORT).show(); } }
- 在
AndroidManifest.xml
中註冊廣播,同時新增上監聽開機啟動廣播需要的許可權。
// 監聽開機啟動需要的許可權 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <application android:name=".App" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> // 靜態註冊廣播 <receiver android:name=".launch_model.BootCompleteReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> </receiver> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application>
以上是兩個系統廣播的靜態註冊和動態註冊使用例子,上面的使用都不難,唯一找不到方向的是這幾個許可權去哪找?Android 官網應該有介紹,我就沒去找了,下面給出幾個 常見的系統廣播對應的許可權和 action
幾個 常見的系統廣播對應的許可權和 action
詳細使用見這篇文章 ofollow,noindex">Android 之 BroadcastReceiver (二) 常見的幾個系統廣播
常見的系統廣播
- 系統啟動完成
- 網路狀態
- 電量變化
- 監聽SD卡狀態
- 監聽應用的安裝、解除安裝、更新
常見的 Action 常量
在 <intent-filter></intent-filter>
中定義個 action
,這裡的 action 是廣播的唯一標識,系統的廣播能夠發給所有監聽了這個廣播訊息的軟體監聽者,這也驗證了廣播是 跨程序的一種通訊方式 。
ACTION_TIME_CHANGED ACTION_DATE_CHANGED ACTION_TIMEZONE_CHANGED ACTION_BOOT_COMPLETED ACTION_PACKAGE_ADDED ACTION_PACKAGE_CHANGED ACTION_PACKAGE_REMOVED ACTION_PACKAGE_RESTARTED ACTION_PACKAGE_DATA_CLEARED ACTION_BATTERY_CHANGED ACTION_BATTERY_LOW ACTION_POWER_CONNECTED ACTION_POWER_DISCONNECTED ACTION_SHUTDOWN
自定義廣播---標準廣播
主要是用於重新整理 UI
,在自定義廣播中,可以傳送標準廣播和有序廣播。標準廣播是高效的,但是是不可被打斷的,無序的。有序廣播是可以被打斷,有序的。
實現方式同上面介紹的監聽開機啟動,唯一不同的是 action
是我們自定義的 action
,完整程式碼如下
// 定義一個廣播 public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "自定義廣播", Toast.LENGTH_SHORT).show(); } } // 靜態註冊廣播 <receiver android:name=".launch_model.MyBroadcastReceiver" android:enabled="true" android:exported="true"> <intent-filter> <!--這裡的 action 一般以類名的具體路徑命名--> <action android:name="com.dong.test1.launch_model.MyBroadcastReceiver"/> </intent-filter> </receiver> // 點選按鈕傳送廣播 Button btnSendBroad = findViewById(R.id.btn_send_broad); btnSendBroad.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 廣播的 action Intent intent = new Intent("com.dong.test1.launch_model.MyBroadcastReceiver"); // 這裡的 intent 可以攜帶一些資料 使用 intent.putXXX() 方法傳遞 sendBroadcast(intent); } });
自定義廣播---有序廣播
前面介紹的廣播都是無序的,那麼如何實現廣播的有序傳送和接受呢?也很簡單,只需要兩步即可
- 給所有要監聽該廣播的action 設定為一樣的值。
- 在
<intent-filter android:priority="100">
中新增priority='值'
值越大優先順序越高。
<receiver android:name=".launch_model.MyBroadcastReceiver" android:enabled="true" android:exported="true"> <intent-filter android:priority="100"> <!--這裡的 action 一般以類名的具體路徑命名--> <action android:name="com.dong.test1.launch_model.MyBroadcastReceiver"/> </intent-filter> </receiver>
這時候如果在接受器中接受到訊息不想往下傳遞,可以使用
public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "自定義廣播", Toast.LENGTH_SHORT).show(); // 中斷廣播訊息,在廣播優先順序低於這條廣播接收者之後的的廣播都收不到訊息。 abortBroadcast(); } }
自定義廣播---本地廣播
上面介紹的廣播都屬於全域性廣播,也就是別人只要知道我們的 action
就可以給我們的廣播一直髮送訊息,這是不太安全的,所以 Android 引入了本地廣播機制。它主要是通過 LocalBroadcastManager
來對廣播進行管理。實現的簡單例子如下:
// 本地廣播接收者 class LocalReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "本地廣播", Toast.LENGTH_SHORT).show(); } } private LocalReceiver mLocalReceiver; private LocalBroadcastManager mLocalBroadcastManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_a); // 獲取到本地廣播管理者例項 mLocalBroadcastManager = LocalBroadcastManager.getInstance(this); Button btnSendBroad = findViewById(R.id.btn_send_broad); btnSendBroad.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent("com.dong.test1.launch_model.MyBroadcastReceiver"); // 通過本地廣播管理來發送廣播 mLocalBroadcastManager.sendBroadcast(intent); } }); IntentFilter intentFilter = new IntentFilter(); mLocalReceiver = new LocalReceiver(); // 通過本地廣播管理來註冊廣播mLocalBroadcastManager.registerReceiver(mLocalReceiver,intentFilter); } @Override protected void onDestroy() { super.onDestroy(); // 通過本地廣播管理來登出廣播 mLocalBroadcastManager. unregisterReceiver(mLocalReceiver); }
本地廣播的使用和動態註冊廣播的使用是類似的,只是這裡多了一個 LocalBroadcastManager
管理類,它的註冊、登出以及廣播的傳送都是通過管理類的物件去操作。
本文完~