BroadcastReceiver也就是“廣播接收者”的意思,它是用來接收來自系統和應用中的廣播。
在Android中,Broadcast是一種廣泛運用的在應用程式之間傳輸資訊的機制。而BroadcastReceiver是對發送出來的 Broadcast進行過濾接受並響應的一類組件。
下面將詳細的闡述如何發送Broadcast和使用BroadcastReceiver過濾接收的過程:
(1)首先在需要發送資訊的地方,把要發送的資訊和用於過濾的資訊(如Action、Category)裝入一個Intent對象,然後通過調用 sendOrderBroadcast()或sendStickyBroadcast()方法,把 Intent對象以廣播方式發送出去。
(2)當Intent發送以後,所有已經註冊的BroadcastReceiver會檢查註冊時的IntentFilter是否與發送的Intent相匹配,若匹配則就會調用BroadcastReceiver的onReceive()方法。所以當我們定義一個BroadcastReceiver的時候,都需要實現onReceive()方法。
註冊BroadcastReceiver有兩種方式
靜態註冊:在AndroidManifest.xml中用標籤生命註冊,並在標籤內用標籤設定過濾器。
<receiver android:name="myRecevice"> //繼承BroadcastReceiver,重寫onReceiver方法 <intent-filter> <action android:name="com.lc.test"/> //使用過濾器,接收指定action廣播 </intent-filter> </receiver>
動態註冊: 使用IntentFilter在代碼中動態註冊一個廣播
IntentFilter intentFilter = new IntentFilter(); //為BroadcastReceiver指定action,使之用於接收同action的廣播 intentFilter.addAction(String); registerReceiver(BroadcastReceiver,intentFilter);
另外值得注意的是,當我們使用動態註冊時候,當這個Activity或Service被銷毀時如果沒有解除註冊,系統會報一個異常,提示我們是否忘記解除註冊了,所以我們需要在onDestroy()方法中進行解除註冊,一般:在onStart中註冊,onStop中取消unregisterReceiver:
@Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(receiver); }
指定廣播目標Action:Intent intent = new Intent(actionString);
並且可通過Intent攜帶訊息 :intent.putExtra(“msg”, “hi,我通過廣播發送訊息了”);
發送廣播訊息:Context.sendBroadcast(intent )
其中在動態註冊中可將BroadcastReceiver的繼承類進行封裝,添加建構函式和BroadcastReceiver註冊
BroadcastReceiver的案例示範
首先我們建立一個類MyBroadcastReceiver用於繼承BroadcastReceiver:
這裡重寫了一個方法就是接受廣播的意圖並匹配:
//定義的為:public static final String //ACTION_REGISTER_SUCCESS_FINISH="register.success.finish";Constants.ACTION_REGISTER_SUCCESS_FINISH.equals(intent.getAction())
這裡是常量:定義如下:
public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent != null && Constants.ACTION_REGISTER_SUCCESS_FINISH.equals(intent.getAction())) { finish(); } } }
(1)接下裡我們就通過“動態註冊”的方式使用:
private MyBroadcastReceiver receiver = new MyBroadcastReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction(BmobConstants.ACTION_REGISTER_SUCCESS_FINISH); //添加action registerReceiver(receiver, filter); //註冊
(2)靜態註冊的話是現在資訊清單檔中添加:
<receiver android:name=".MyBroadcastReceiver"> <intent-filter> <action android:name="register.success.finish"/> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </receiver>
(2-1)我們就可以使用代碼了:
Intent intent = new Intent("register.success.finish"); intent.putExtra("msg", "hello receiver."); sendBroadcast(intent); //發送廣播
普通廣播(Normal Broadcast)
普通廣播對於多個接收者來說是完全非同步,通常每個接收者都無需等待即可以接收到廣播,接收者相互之間不會有影響。對於這種廣播,接收者無法終止廣播,即無法阻止其他接收者的接收動作。為了驗證以上論斷,我們建立三個BroadcastReceiver,示範一下這個過程,FirstReceiver、SecondReceiver和ThirdReceiver的代碼如下:
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; public class FirstReceiver extends BroadcastReceiver { private static final String TAG = "NormalBroadcast"; @Override public void onReceive(Context context, Intent intent) { String msg = intent.getStringExtra("msg"); Log.i(TAG, "FirstReceiver: " + msg); } }
public class SecondReceiver extends BroadcastReceiver { private static final String TAG = "NormalBroadcast"; @Override public void onReceive(Context context, Intent intent) { String msg = intent.getStringExtra("msg"); Log.i(TAG, "SecondReceiver: " + msg); } }
public class ThirdReceiver extends BroadcastReceiver { private static final String TAG = "NormalBroadcast"; @Override public void onReceive(Context context, Intent intent) { String msg = intent.getStringExtra("msg"); Log.i(TAG, "ThirdReceiver: " + msg); } }
然後再次點擊發送按鈕,發送一條廣播,控制台列印如下:
看來這三個接收者都接收到這條廣播了,我們稍微修改一下三個接收者,在onReceive方法的最後一行添加以下代碼,試圖終止廣播:
再次點擊發送按鈕,我們會發現,控制台中三個接收者仍然都列印了自己的日誌,表明接收者並不能終止廣播。
有序廣播(Ordered Broadcast)
有序廣播比較特殊,它每次只發送到優先順序較高的接收者那裡,然後由優先順序高的接受者再傳播到優先順序低的接收者那裡,優先順序高的接收者有能力終止這個廣播。
為了示範有序廣播的流程,我們修改一下上面三個接收者的代碼,如下:
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.util.Log; public class FirstReceiver extends BroadcastReceiver { private static final String TAG = "OrderedBroadcast"; @Override public void onReceive(Context context, Intent intent) { String msg = intent.getStringExtra("msg"); Log.i(TAG, "FirstReceiver: " + msg); Bundle bundle = new Bundle(); bundle.putString("msg", msg + "@FirstReceiver"); setResultExtras(bundle); } }
public class SecondReceiver extends BroadcastReceiver { private static final String TAG = "OrderedBroadcast"; @Override public void onReceive(Context context, Intent intent) { String msg = getResultExtras(true).getString("msg"); Log.i(TAG, "SecondReceiver: " + msg); Bundle bundle = new Bundle(); bundle.putString("msg", msg + "@SecondReceiver"); setResultExtras(bundle); } }
public class ThirdReceiver extends BroadcastReceiver { private static final String TAG = "OrderedBroadcast"; @Override public void onReceive(Context context, Intent intent) { String msg = getResultExtras(true).getString("msg"); Log.i(TAG, "ThirdReceiver: " + msg); } }
我們注意到,在FirstReceiver和SecondReceiver中最後都使用了setResultExtras方法將一個Bundle對象設定為結果集對象,傳遞到下一個接收者那裡,這樣以來,優先順序低的接收者可以用getResultExtras擷取到最新的經過處理的資訊集合。
代碼改完之後,我們需要為三個接收者註冊廣播位址,我們修改一下AndroidMainfest.xml檔案:
<receiver android:name=".FirstReceiver"> <intent-filter android:priority="1000"> <action android:name="android.intent.action.MY_BROADCAST"/> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </receiver> <receiver android:name=".SecondReceiver"> <intent-filter android:priority="999"> <action android:name="android.intent.action.MY_BROADCAST"/> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </receiver> <receiver android:name=".ThirdReceiver"> <intent-filter android:priority="998"> <action android:name="android.intent.action.MY_BROADCAST"/> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </receiver>
我們看到,現在這三個接收者的多了一個android:priority屬性,並且依次減小。這個屬性的範圍在-1000到1000,數值越大,優先順序越高。
現在,我們需要修改一下發送廣播的代碼,如下:
public void send(View view) { Intent intent = new Intent("android.intent.action.MY_BROADCAST"); intent.putExtra("msg", "hello receiver."); sendOrderedBroadcast(intent, "scott.permission.MY_BROADCAST_PERMISSION"); }
注意,使用sendOrderedBroadcast方法發送有序廣播時,需要一個許可權參數,如果為null則表示不要求接收者聲明指定的許可權,如果不為null,則表示接收者若要接收此廣播,需聲明指定許可權。這樣做是從安全形度考慮的,例如系統的簡訊就是有序廣播的形式,一個應用可能是具有攔截垃圾簡訊的功能,當簡訊到來時它可以先接受到簡訊廣播,必要時終止廣播傳遞,這樣的軟體就必須聲明接收簡訊的許可權。
所以我們在AndroidMainfest.xml中定義一個許可權:
<permission android:protectionLevel="normal" android:name="scott.permission.MY_BROADCAST_PERMISSION" />
然後聲明使用了此許可權:
<uses-permission android:name="scott.permission.MY_BROADCAST_PERMISSION" />
關於這部分如果有不明白的地方可以參考我之前寫過的一篇文章:Android聲明和使用許可權
然後我們點擊發送按鈕發送一條廣播,控制台列印如下:
我們看到接收是按照順序的,第一個和第二個都在結果集中加入了自己的標記,並且向優先順序低的接收者傳遞下去。
既然是順序傳遞,試著終止這種傳遞,看一看效果如何,我們修改FirstReceiver的代碼,在onReceive的最後一行添加以下代碼:
然後再次運行程式,控制台列印如下:
此次,只有第一個接收者執行了,其它兩個都沒能執行,因為廣播被第一個接收者終止了。
上面就是BroadcastReceiver的介紹,下面我將會舉幾個常見的例子加深一下大家對廣播的理解和應用:
1.開機啟動服務
我們經常會有這樣的應用場合,比如訊息推送服務,需要實現開機啟動的功能。要實現這個功能,我們就可以訂閱系統“啟動完成”這條廣播,接收到這條廣播後我們就可以啟動自己的服務了。我們來看一下BootCompleteReceiver和MsgPushService的具體實現:
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; public class BootCompleteReceiver extends BroadcastReceiver { private static final String TAG = "BootCompleteReceiver"; @Override public void onReceive(Context context, Intent intent) { Intent service = new Intent(context, MsgPushService.class); context.startService(service); Log.i(TAG, "Boot Complete. Starting MsgPushService..."); } }
import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.util.Log; public class MsgPushService extends Service { private static final String TAG = "MsgPushService"; @Override public void onCreate() { super.onCreate(); Log.i(TAG, "onCreate called."); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand called."); return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent arg0) { return null; } }
然後我們需要在AndroidManifest.xml中配置相關資訊:
<!-- 開機廣播接受者 --> <receiver android:name=".BootCompleteReceiver"> <intent-filter> <!-- 註冊開機廣播位址--> <action android:name="android.intent.action.BOOT_COMPLETED"/> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </receiver> <!-- 訊息推送服務 --> <service android:name=".MsgPushService"/>
我們看到BootCompleteReceiver註冊了“android.intent.action.BOOT_COMPLETED”這個開機廣播位址,從安全形度考慮,系統要求必須聲明接收開機啟動廣播的許可權,於是我們再聲明使用下面的許可權:
經過上面的幾個步驟之後,我們就完成了開機啟動的功能,將應用運行在模擬器上,然後重啟模擬器,控制台列印如下:
如果我們查看已啟動並執行服務就會發現,MsgPushService已經運行起來了。
2.網路狀態變化
在某些場合,比如使用者瀏覽網路資訊時,網路突然斷開,我們要及時地提醒使用者網路已斷開。要實現這個功能,我們可以接收網路狀態改變這樣一條廣播,當由串連狀態變為斷開狀態時,系統就會發送一條廣播,我們接收到之後,再通過網路的狀態做出相應的操作。下面就來實現一下這個功能:
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.util.Log; import android.widget.Toast; public class NetworkStateReceiver extends BroadcastReceiver { private static final String TAG = "NetworkStateReceiver"; @Override public void onReceive(Context context, Intent intent) { Log.i(TAG, "network state changed."); if (!isNetworkAvailable(context)) { Toast.makeText(context, "network disconnected!", 0).show(); } } /** * 網路是否可用 */ public static boolean isNetworkAvailable(Context context) { ConnectivityManager mgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo[] info = mgr.getAllNetworkInfo(); if (info != null) { for (int i = 0; i < info.length; i++) { if (info[i].getState() == NetworkInfo.State.CONNECTED) { return true; } } } return false; } }
再註冊一下這個接收者的資訊:
<receiver android:name=".NetworkStateReceiver"> <intent-filter> <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </receiver>
因為在isNetworkAvailable方法中我們使用到了網路狀態相關的API,所以需要聲明相關的許可權才行,下面就是對應的許可權聲明:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
我們可以測試一下,比如關閉WiFi,看看有什麼效果。
3.電量變化
如果我們閱讀軟體,可能是全屏閱讀,這個時候使用者就看不到剩餘的電量,我們就可以為他們提供電量的資訊。要想做到這一點,我們需要接收一條電量變化的廣播,然後擷取百分比資訊,這聽上去挺簡單的,我們就來實現以下:
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.BatteryManager; import android.util.Log; public class BatteryChangedReceiver extends BroadcastReceiver { private static final String TAG = "BatteryChangedReceiver"; @Override public void onReceive(Context context, Intent intent) { int currLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); //當前電量 int total = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 1); //總電量 int percent = currLevel * 100 / total; Log.i(TAG, "battery: " + percent + "%"); } }
然後再註冊一下廣播接地址資訊就可以了:
<receiver android:name=".BatteryChangedReceiver"> <intent-filter> <action android:name="android.intent.action.BATTERY_CHANGED"/> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </receiver>
當然,有些時候我們是要立即擷取電量的,而不是等電量變化的廣播,比如當閱讀軟體開啟時立即顯示出電池電量。我們可以按以下方式擷取:
Intent batteryIntent = getApplicationContext().registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); int currLevel = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); int total = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 1); int percent = currLevel * 100 / total; Log.i("battery", "battery: " + percent + "%");
以上就是本文的全部內容,希望對大家的學習有所協助。