Android中廣播只要分爲兩種:標準廣播和有序廣播
標準廣播(Normal broadcasts):一種完全異步執行的廣播,在廣播發出之後,所有的廣播接收器幾乎都會在同一時刻接收到這條廣播消息,因此它們之間沒有任何先後順序可言。這種廣播的效率會比較高,但同時意味着它無法被截斷。
有序廣播(Ordered broadcasts):一種同步執行的廣播,在廣播發出之後,同一時刻只會有一個廣播接收器能夠收到這條廣播消息,當這個廣播接收器中的邏輯執行完畢後,廣播纔會繼續傳遞。所以此時的廣播接收器是有先後順序的,優先級較高的廣播接收器就可以先收到廣播消息,並且前面的廣播接收器可以截斷正在傳遞的廣播,這樣後面的廣播接收器就無法收到廣播消息了。
動態註冊監聽網絡變化
- public class MainActivity extends Activity {
- private IntentFilter intentFilter;
- private NetworkChangeReceiver networkChangeReceiver;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- intentFilter = new IntentFilter();
- intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
- networkChangeReceiver = new NetworkChangeReceiver();
- registerReceiver(networkChangeReceiver, intentFilter);
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- unregisterReceiver(networkChangeReceiver);
- }
- //內部類
- class NetworkChangeReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Toast.makeText(context, "network changes",
- Toast.LENGTH_SHORT).show();
- }
- }
- }
然後觀察 onCreate() 方法,首先我們創建了一個 IntentFilter 的實例,並給它添加了一個值爲 android.net.conn.CONNECTIVITY_CHANGE 的 action,爲什麼要添加這個值呢?因爲當網絡狀態發送變化時,系統發出的正是這一條值爲 android.net.conn.CONNECTIVITY_CHANGE 的廣播,也就是說我們的廣播接收器想要監聽什麼廣播,就在這裏添加相應的 action 就行了。接下來創建了一個 NetworkChangeReceiver 的實例,然後調用 registerReceiver() 方法進行註冊,將 NetworkChangeReceiver 的實例和 IntentFilter 的實例都傳了進去,這樣 NetworkChangeReceiver 就會收到所有值爲 android.net.conn.CONNECTIVITY_CHANGE 的廣播,也就實現了監聽網絡變化的功能。
動態註冊的廣播接收器一定都要取消註冊才行,這裏我們是在 onDestroy() 方法中通過調用 unregisterReceiver() 方法來實現的。
不過只是提醒網絡發生了變化還不夠人性化,最好是能準確地告訴用戶當前是有網絡還是沒有網絡,因此我們還需要對上面的代碼進行進一步的優化。修改 MainActivity 中的代碼,如下所示:
在 onReceive() 方法中,首先通過 getSystemService() 方法得到了 ConnectivityManager 的實例,這是一個系統服務類,專門用於管理網絡連接的。然後調用它的 getActiveNetworkInfo() 方法可以得到 NetworkInfo 的實例,接着調用 NetworkInfo 的 isAvailable() 方法,就可以判斷出當前是否有網絡了,最後我們還是通過 Toast 的方式對用戶進行提示。
另外,Android 系統爲了保證應用程序的安全性做了規定,如果程序需要訪問一些系統的關鍵性信息,必須在配置文件中聲明權限纔可以,否則程序將會直接崩潰,比如這裏查詢系統的網絡狀態就是需要聲明權限的。打開 AndroidManifest.xml 文件,在裏面加入如下權限就可以查詢系統網絡狀態了:
靜態註冊實現開機啓動
- public class BootCompleteReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show();
- }
- }
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.broadcasttest"
- android:versionCode="1"
- android:versionName="1.0" >
- ......
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- ......
- <receiver android:name=".BootCompleteReceiver" >
- <intent-filter>
- <action android:name="android.intent.action.BOOT_COMPLETED" />
- </intent-filter>
- </receiver>
- </application>
- </manifest>
終於,<application> 標籤內出現了一個新的標籤<receiver>,所有的靜態註冊的廣播接收器都是在這裏進行註冊的。它的用法其實和<activity>標籤非常相似,首先通過 android:name 來指定具體註冊哪一個廣播接收器,然後在 <intent-filter> 標籤里加入想要接收的廣播就行了,由於 Android 系統啓動完成後會發出一條值爲 android:intent.action.BOOT_COMPLETED 的廣播,因此我們在這裏添加了相應的 action。
另外,監聽系統開機廣播也是需要聲明權限的,可以看到,我們使用 <uses-permission> 標籤又加入了一條 android.permission.RECEIVE_BOOT_COMPLETED 權限。
發送自定義廣播
1.發送標準廣播
- public class MyBroadcastReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Toast.makeText(context, "received in MyBroadcastReceive",
- Toast.LENGTH_SHORT).show();
- }
- }
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.broadcasttest"
- android:versionCode="1"
- android:versionName="1.0" >
- ......
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- ......
- <receiver android:name=".MyBroadcastReceiver">
- <intent-filter>
- <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
- </intent-filter>
- </receiver>
- </application>
- </manifest>
- @Override
- public void onClick(View v) {
- Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
- sendBroadcast(intent);
- }
發送有序廣播
- @Override
- public void onClick(View v) {
- Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
- sendOrderedBroadcast(intent, null); //第二個參數是一個與權限相關的字符串
- }
- <receiver android:name=".MyBroadcastReceiver">
- <intent-filter android:priority="100" > //優先級設成100
- <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
- </intent-filter>
- </receiver>
截斷有序廣播
- public class MyBroadcastReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Toast.makeText(context, "received in MyBroadcastReceive",
- Toast.LENGTH_SHORT).show();
- abortBroadcast();
- }
- }
使用本地廣播
- public class MainActivity extends Activity {
- private IntentFilter intentFilter;
- private LocalReceiver localReceiver; //
- private LocalBroadcastManager localBroadcastManager; //
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- localBroadcastManager = LocalBroadcastManager.getInstance(this); // 獲取實例
- Button button = (Button) findViewById(R.id.button);
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(
- "com.example.broadcasttest.LOCAL_BROADCAST");
- localBroadcastManager.sendBroadcast(intent); // 發送本地廣播
- }
- });
- intentFilter = new IntentFilter();
- intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
- localReceiver = new LocalReceiver();
- localBroadcastManager.registerReceiver(localReceiver, intentFilter); // 註冊本地廣播監聽器
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- localBroadcastManager.unregisterReceiver(localReceiver);
- }
- class LocalReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Toast.makeText(context, "received local broadcast",
- Toast.LENGTH_SHORT).show();
- }
- }
- }
- 可以明確地知道正在發送的廣播不會離開我們的程序,因此不需要擔心機密數據泄露的問題。
- 其他的程序無法將廣播發送到我們的程序的內部,因此不需要擔心會有安全漏洞的隱患。
- 發送本地廣播比起發送系統全局廣播將會更加高效。