標籤:
什麼是Broadcast
Broadcast即廣播,在Android廣播是非常重要的功能。例如我們想在系統開機之後做某些事情、監控手機的電量、監控手機的網路狀態等等,這些功能都需要用到廣播。當然我們也可以自訂廣播。
自訂廣播
通常實現一個簡單的自訂廣播可以通過如下幾個步驟:
- 建立一個類繼承android.content.BroadcastReceiver,並實現onReceive方法
- 在AndroidManifest.xml中註冊廣播
- 通過Context的registerReceiver等方法註冊廣播
- 調用Context的sendBroadcast等方法發送廣播,在onReceive方法中處理廣播
- 調用Context的unregisterReceiver等方法登出廣播
我們通過代碼來解釋一下上面的步驟:
1.建立一個類繼承android.content.BroadcastReceiver,並實現onReceive方法
package com.mark.broadcastreciver;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.util.Log;/** * 建立一個自訂廣播接收者需要繼承android.content.BroadcastReceiver, * 並實現onReceive方法即可。 */public class MyReceiver extends BroadcastReceiver { private final static String TAG = MyReceiver.class.getSimpleName(); public MyReceiver() { } /** * 當接收到廣播之後會調用此方法 * @param context 內容物件 * @param intent 調用sendBroadcast(intent)傳入的Intent執行個體,其中包含了action、和其他附帶資訊 */ @Override public void onReceive(Context context, Intent intent) { // 擷取msg對應的資料 String msg = intent.getStringExtra("msg"); // 列印msg資料 Log.i(TAG, "msg = " + msg); // 列印action字串 Log.i(TAG, "action = " + intent.getAction()); }}
2.在AndroidManifest.xml中註冊廣播
<application> <receiver android:name=".MyReceiver"> </receiver></application>
3.通過Context的registerReceiver等方法註冊廣播
4.調用Context的sendBroadcast等方法發送廣播,在onReceive方法中處理廣播
5.調用Context的unregisterReceiver等方法登出廣播
package com.mark.broadcastreciver;import android.content.BroadcastReceiver;import android.content.Intent;import android.content.IntentFilter;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;public class MainActivity extends AppCompatActivity { BroadcastReceiver registerReceiver; IntentFilter intentFilter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 建立BroadcastReceiver執行個體 registerReceiver = new MyReceiver(); // 建立IntentFilter,指定其action為com.mark.broadcast.receiver,這個可以自己定義 intentFilter = new IntentFilter("com.mark.broadcast.receiver"); // 註冊廣播將registerReceiver與intentFilter關聯, // registerReceiver可以接收到action為com.mark.broadcast.receiver的廣播 registerReceiver(registerReceiver, intentFilter); findViewById(R.id.btnRegister).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 發送廣播 // 建立Intent,指定其action為com.mark.broadcast.receiver,與registerReceiver關聯的action一致 Intent intent = new Intent("com.mark.broadcast.receiver"); // 指定要發送的資訊 intent.putExtra("msg", "Hello, a new message."); sendBroadcast(intent); } }); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(registerReceiver); }}
通過上述的步驟我們就實現了一個自訂廣播,當我們點擊Button在控制台中可以看到如下資訊:
04-13 17:12:28.591 16882-16882/com.mark.broadcastreciver I/MyReceiver: msg = Hello, a new message.04-13 17:12:28.591 16882-16882/com.mark.broadcastreciver I/MyReceiver: action = com.mark.broadcast.receiver
註冊廣播
註冊廣播的方式有兩種:靜態註冊和動態註冊。
靜態註冊
這種方法是在配置AndroidManifest.xml設定檔中註冊,通過這種方式註冊的廣播為常駐型廣播,也就是說如果應用程式關閉了,有相應事件觸發,程式還是會被系統自動調用運行。例如:
<!-- 在設定檔中註冊BroadcastReceiver能夠匹配的Intent --><receiver android:name=“.MyReceiver"> <intent-filter> </action> <action android:name=“com.mark.broadcast.reveiver”/> <category android:name="android.intent.category.DEFAULT"></category> </intent-filter></receiver>
動態註冊
這種方法是通過代碼在.Java檔案中進行註冊。通過這種方式註冊的廣播為非常駐型廣播,即它會跟隨Activity的生命週期,所以在Activity結束前我們需要調用unregisterReceiver(receiver)方法移除它。例如:
// 建立BroadcastReceiver執行個體registerReceiver = new MyReceiver(); // 建立IntentFilter,指定其action為com.mark.broadcast.receiver,這個可以自己定義 intentFilter = new IntentFilter("com.mark.broadcast.receiver"); // 註冊廣播將registerReceiver與intentFilter關聯, // registerReceiver可以接收到action為com.mark.broadcast.receiver的廣播registerReceiver(registerReceiver, intentFilter);
注意:如果我們在Activity中註冊了BroadcastReceiver,當這個Activity銷毀的時候要主動撤銷註冊否則會出現異常。方法如下:
@Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(registerReceiver); }
廣播的類型
Broadcast的類型有兩種:普通廣播和有序廣播。
Normal broadcasts (普通廣播)
Normal broadcasts是完全非同步可以同一時間被所有的接收者接收到。訊息的傳遞效率比較高。但缺點是接收者不能講接收的訊息的處理資訊傳遞給下一個接收者也不能停止訊息的傳播。多個普通廣播設定相同的IntentFilter,則先註冊的先收到廣播。
Ordered broadcasts (有序廣播)
Ordered broadcasts的接收者按照一定的優先順序進行訊息的接收。如:A,B,C的優先順序依次降低,那麼訊息先傳遞給A,在傳遞給B,最後傳遞給C。優先順序別聲明在中,取值為[-1000,1000]數值越大優先順序別越高。優先順序也可通過filter.setPriority(10)方式設定。
另外Ordered broadcasts的接收者可以通過abortBroadcast()的方式取消廣播的傳播,也可以通過setResultData和setResultExtras方法將處理的結果存入到Broadcast中,傳遞給下一個接收者。然後,下一個接收者通過getResultData()和getResultExtras(true)接收高優先順序的接收者存入的資料。
例如:
<receiver android:name=".FirstReceiver"> <intent-filter android:priority="999"> <action android:name="com.mark.broadcast.receiver" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter></receiver><receiver android:name=".MyReceiver" > <intent-filter android:priority="1000"> <action android:name="com.mark.broadcast.receiver" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter></receiver>
如上兩個receiver我們分別設定為priority為999,和1000,及時MyReceiver是後註冊的,但是其優先順序比FirstReceiver高,則MyReceiver會先處理廣播。
sendOrderedBroadcast 發送有序廣播
sendOrderedBroadcast(intent, receiverPermission)方法接收兩個參數,比普通廣播的發送方式多了一個receiverPermission參數,這是一個String類型的參數,代表具有這個許可權的Receiver才能處理收到此廣播。如果為null則表明不要求接受者聲明指定許可權。我們來看一下具體的操作。
首先我們要自訂一個許可權,例如:
<permission android:name="com.permissions.MY_BROADCAST_RECEIVER" android:protectionLevel="normal" />
然後我們要是當前的程式具有此許可權:例如:
<uses-permission android:name="com.permissions.MY_BROADCAST_RECEIVER" />
這樣當前程式就擁有此許可權了。
我們在發送有序廣播是指定其許可權為com.permissions.MY_BROADCAST_RECEIVER,注意拼字不要有錯誤,最好是複製過來。發送廣播如下:
// 建立Intent,指定其action為com.mark.broadcast.receiver,與registerReceiver關聯的action一致Intent intent = new Intent("com.mark.broadcast.receiver");// 指定要發送的資訊intent.putExtra("msg", "Hello, a new message.");sendOrderedBroadcast(intent, "com.permissions.MY_BROADCAST_RECEIVER");
這樣我們發送廣播,並指定其許可權為com.permissions.MY_BROADCAST_RECEIVER,因為當前的程式已經使用了此許可權了,所以當前程式中的receiver是可以接收並處理此條廣播的。否則不能接收此條廣播。此處的許可權體現了android對安全性的重視。
sendStickyBroadcast 粘性廣播
粘性廣播與其他的廣播方式最大的不同在於“非同步”,也就是說當一個粘性廣播發出去後,可以沒有Receiver進行處理,但是這個廣播還會一直存在,假如過了一段時間之後有Receiver註冊了此廣播,則此Receiver還是可以處理這條廣播的。但是細心的朋友們可以看到sendStickyBroadcast的一系列重載方法的參數中並沒有上面提到的receiverPermission參數,這也將導致粘性廣播在安全性上存在問題。所以在API Level 21 上sendStickyBroadcast方法被標記為deprecated,也就是不建議我們使用粘性廣播了。因為在安全性和其他方面粘性廣播存在很多缺陷。這裡我們也就不在重點討論了。
總結
這裡我們對廣播及廣播接收者進行一個簡單的總結以及在使用時的一些注意事項。
1.發送廣播的方法都是ContextWrapper中的方法,而Activity、Service都是ContextWrapper的子類,所以在它們中都可以發送和註冊廣播
2.onReceive方法中不能做耗時操作,否則也會導致ANR
3.根據實際開發需要,儘可能為廣播增加許可權
4.儘可能避免使用粘性廣播
5.有序廣播的優先順序為【-1000 ~ 1000】,數值越大,優先順序越高
上述描述和某些觀點可能不是正解,僅供參考,歡迎大家指正、批評。
Android-BroadcastReceiver詳解