

標準廣播是完全異步的廣播, 也就是當廣播發出之后, 所有的廣播接收器機會都會在同一時刻接收到這條廣播, 標準廣播無法被攔截。
有序廣播是同步執行的廣播, 也就是當廣播發出之后, 同一時刻只會有一個廣播接收器能夠收到這條廣播消息, 依次傳遞。優先級高的廣播接收器可以優先接收廣播消息, 同時前面的廣播接收器還可以截取正在傳遞的廣播, 這樣后面的廣播就無法收到廣播消息了。
Android內置了很多系統級別的廣播, 比如:手機開機完成后會發出一條廣播, 電池電量發生變化會發出一條廣播, 時間或者時區發生變化會發出一條廣播等等。如果希望接收這些廣播, 就需要使用廣播接收器, 下面來看具體用法。
注冊廣播一般有兩種方式:動態注冊:在代碼中注冊靜態注冊:在AndroidManifest.xml中注冊
首先我們來嘗試一下動態注冊:只需要創建一個類BroadcaseDemo, 讓它繼承自Broadcast-Receiver,并重寫父類的onReceive()方法就行了. onReceive()用來監聽廣播的到來, 具體邏輯也可以在這個方法中處理.
MainActivity.java
public class MainActivity extends AppCompatActivity { 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(); } }}說明: NetWorkChangeReceiver ()繼承BroadcastReceiver, 并重寫了父類的onReceive()方法. 這樣每當網絡發生變化的時候, onReceive()方法就會得到執行.
onCreate()方法, 我們首先創建一個IntentFilter的實例, 并未它添加了一個值為android.net.conn.CONNECTIVITY_CHANGE的action, 為什么要添加這個呢?因為當網絡發生變化的時候, 系統發出的正是一條值為android.net.conn.CONNECTIVITY_CHANGE的廣播. 也就是說我們的廣播接收器想要監聽什么廣播, 就在這里添加相應的action.
接下來創建一個NetWorkChangeReceiver的實例, 然后調用registerReceiver()方法進行注冊.
切記: 動態注冊的廣播接收器一定要取消注冊才行, 這里我們是在onDestroy()方法中調用unregisterReceiver()方法來實現.
運行結果:

下面繼續進行優化, 直接判斷之后告訴用戶, 當前環境是否有網.MainActivity.java
class NetWorkChangeReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // 獲取ConnectivityManager實例, 這是一個系統服務類, 專門用于管理網絡連接 ConnectivityManager connectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); // 調用getActiveNetworkInfo()得到NetworkInfo的實例 NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); // 通過isAvailable()方法判斷當前是否有網絡 if(networkInfo!= null && networkInfo.isAvailable()){ Toast.makeText(context, "network is available", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(context, "network is unavailable", Toast.LENGTH_SHORT).show(); } } }注意: Android系統為了保護用戶設備的安全和隱私, 做了嚴格的規定: 如果程序需要進行一些對用戶來說比較敏感的操作, 就必須在配置文件AndroidManifest.xml中聲明權限才可以, 否者程序會直接崩潰. 比如這里訪問系統的網絡狀態就是需要聲明權限的, 所以我們需要添加下面的代碼.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.junzaivip.broadcastdemo"> <uses-permission android:name="android.permission.access_NETWORK_STATE" />...</manifest>
動態注冊的廣播接收器可以自由的控制注冊與注銷, 在靈活性方面有很大的優勢, 但是它必須在程序啟動之后才能接收到廣播, 因為注冊的邏輯寫在onCreate()方法中. 那么有沒有什么辦法可以讓程序在未啟動的情況下就能接收到廣播呢? 這就需要使用靜態注冊的方式了.
準備實現一個開機啟動的功能, 我們準備讓程序接收一條開機廣播, 當收到這條廣播時, 就可以在onReceive()方法里執行相應的邏輯.
下面我們使用AS的快捷方式來創建一個廣播接收器.

可以看到我們將廣播接收器命名為BootCompleteReceiver, Exported屬性表示是否允許這個廣播接收器接收本程序以外的廣播, Enabled屬性表示是否啟用這個廣播接收器, 默認是勾選的, 然后點擊finish完成創建.
修改完之后的代碼如下:
public class BootCompleteReceive extends BroadcastReceiver { public BootCompleteReceive() { } @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Boot Complete", Toast.LENGTH_SHORT).show(); }}代碼非常簡單, 我們只是在onReceive()方法中使用Toast彈出一段提示信息.
另外, 靜態的廣播接收器一定要在AndroidManifest.xml文件中注冊才可以使用, 不過由于我們是使用的Android Studio的快捷方式創建的廣播接收器, 因此注冊這一步已經被自動完成了. 我們一起去看一看.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.junzaivip.broadcastdemo"> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/APPTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".BootCompleteReceive" android:enabled="true" android:exported="true"></receiver> </application></manifest>說明: 可以看到在</application>的標簽內出現了一個新的標簽<receiver>, 所有的靜態廣播接收器都是在這里進行注冊的, 它的用法其實和<activity>標簽非常相似, 也是通過android:name來指定具體哪一個廣播接收器, 而android:enabled 和android:exported屬性則是根據我們剛才勾選的狀態自動生成的.
不過目前BootCompleteReceive還是不能接收到開機廣播, 我們需要對AndroidManifest.xml文件進行修改才行, 如下所示:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.junzaivip.broadcastdemo"> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".BootCompleteReceive" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED"/> </intent-filter> </receiver> </application></manifest>主要更新了下面的文件:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<intent-filter><action android:name="android.intent.action.LOCKED_BOOT_COMPLETED"/></intent-filter>
說明: 由于Android系統啟動完成后, 會發出android.permission.RECEIVE_BOOT_COMPLETED的廣播, 因此我們在<intent-filter>標簽里添加了相應的action. 另外監聽系統開機廣播也是需要聲明權限的, 所以添加了一條<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>權限.
當然我們程序中只是簡單使用了Toast提示了一段文本信息, 當你真正在項目中使用的時候, 就可以添加自己的邏輯.
需要注意的是, 不要在onReceive()方法中添加過多的邏輯或者進行任何的耗時操作, 因為在廣播接收器中是不允許開啟線程的. onReceive()方法中進行了較長時間而沒有結束時, 程序就會報錯.
廣播接收器, 更多的是扮演一種打開程序或者其他組件的角色, 比如創建一條狀態欄通知, 或者啟動一個服務等.
發送自定義廣播
前面的例子已經了解了接收系統廣播, 接下來我們一起來學習在應用程序中發送自定義廣播.
發送標準廣播
首先定義一個廣播接收器用來接收廣播, 代碼如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.junzaivip.broadcastdemo"> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".MyBroadcastReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.junzaivip.broadcastdemo.MY_BROADCAST"/> </intent-filter> </receiver> </application></manifest>可以看到, 這里讓MyBroadcastReceiver接收一條值為com.junzaivip.broadcastdemo.MY_BROADCAST的廣播, 因此待會兒在發送廣播的時候, 就需要發出一條這樣的廣播.
接下來修改activity_main.xml中的代碼, 如下:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button sendButton = (Button) findViewById(R.id.send_cast); sendButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent("com.junzaivip.broadcastdemo.MY_BROADCAST"); sendBroadcast(intent); } }); }說明: 按鈕的點擊事件里, 加入了自定義廣播的邏輯. 首先構建出一個對象Intent對象, 并把要發送廣播的值傳入, 然后調用sendBroadcast()方法將廣播發送出去, 這樣所有監聽com.junzaivip.broadcastdemo.MY_BROADCAST這條廣播的廣播接收器就會收到消息. 此時發出去的廣播就是一條標準廣播. 由于廣播是通過Intent進行傳遞, 所以還可以在Intent中添加一些數據傳遞給廣播接收器.
運行效果:
擴展 通過Intent來傳遞和接收數據方式:
通過intent來傳遞數據(字符串):
Intent intent = new Intent();intent.setClass(DetailActivity.this, HistoryActivity.class);intent.putExtra("","");intent.putExtra("","");intent.putExtra("","");startActivity(intent);
通過intent來傳遞對象, 則在javabean需要實現序列化接口
import java.io.Serializable;public class DetailModel implements Serializable{}Intent intent = new Intent();intent.setClass(LeaderScheduleClientDetailActivity.this, LeaderScheduleContactHistoryActivity.class);Bundle bundle = new Bundle();bundle.putSerializable("contactHistorys",item);intent.putExtras(bundle);startActivity(intent);
接收intent傳遞過來的字符串:
true_exhibitionID = getIntent().getStringExtra("true_exhibitionID");
接收intent傳遞過來的對象
Bundle bundle = getIntent().getExtras();model = (GroupModel) bundle.getSerializable("groupModel");
發送有序廣播
因為廣播是一種可以跨進程的通信方式, 因此我們應用程序內發出的廣播, 其他的應用程序應該也是可以收到的.
下面我們就來一個例子, 通過第一個程序發送一個廣播, 打開另外一個程序, 并且在第二個程序中顯示自定義內容.
在另外一個程序中添加AnotherBroadcastReceiver, 代碼如下:
public class AnotherBroadcastReceiver extends BroadcastReceiver { public AnotherBroadcastReceiver() { } @Override public void onReceive(Context context, Intent intent) { Intent i = new Intent(); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); i.setClass(context,MainActivity.class); context.startActivity(i); Toast.makeText(context, "另外一個廣播", Toast.LENGTH_SHORT).show(); }}在AndroidManifest.xml中配置:
<receiver android:name=".AnotherBroadcastReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.junzaivip.broadcastdemo.MY_BROADCAST"/> </intent-filter></receiver>說明: Intent i = new Intent();i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);i.setClass(context,MainActivity.class);context.startActivity(i); 這一段就是核心代碼, 用來打開另外一個程序.
這樣就可以通過廣播打開另外一個應用程序了, 也可以顯示內容. 下面是效果演示:
這樣就強有力的證明了, 我們的應用程序發出的廣播是可以被其他應用程序接收到的.
不過到目前為止, 程序里發出的廣播都還是標準廣播, 現在我們來嘗試一下發送有序廣播.重新回到broadcastDemo項目, 然后修改MainActivity中的代碼, 如下:
將 sendBroadcast(intent); 修改為 sendOrderedBroadcast(intent,null);
可以看到發送有序廣播只需要改動一行代碼, 即將sendBroadcast()方法改成sendOrderedBroadcast()方法.
sendOrderedBroadcast()方法接收兩個參數, 第一個參數仍然是Intent, 第二個參數是一個與權限相關的字符串, 這里傳入null就行了. 現在重新運行程序, 并點擊Send Broadcast按鈕, 你會發現兩個應用程序都還是可以接收到這條廣播.
看上去貌似沒什么區別, 這個時候廣播接收器是有先后順序的. 而且前面的廣播接收器還可以將廣播截斷, 以阻止其繼續傳播.
通過android:priority屬性給廣播接收器設置優先級, 優先級比較高的廣播就可以先收到廣播. 下面給它設置了100, 以保證它一定會會在另一個之前收到廣播. 同時它也有權限來決定是否允許廣播繼續傳遞.AndroidManifest.xml
<receiver android:name=".MyBroadcastReceiver" android:enabled="true" android:exported="true"> <intent-filter android:priority="100"> <action android:name="com.junzaivip.broadcastdemo.MY_BROADCAST"/> </intent-filter> </receiver>下面我們來配置讓第一個應用程序阻止繼續傳遞.
public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "歡迎關注公眾號:史慧君, 測試接收一個自定義廣播", Toast.LENGTH_SHORT).show(); abortBroadcast(); }}說明:abortBroadcast();表示將這條廣播階段, 后面的廣播接收器將無法再繼續接收這條廣播.
新聞熱點
疑難解答