今天我們一起來探讨下安卓中BroadcastReceiver元件以及詳細分析下它的兩種注冊方式。
BroadcastReceiver也就是“廣播接收者”的意思,顧名思義,它就是用來接收來自系統和應用中的廣播。在Android系統中,廣播展現在方方面面,例如當開機完成後系統會産生一條廣播,接收到這條廣播就能實作開機啟動服務的功能;當網絡狀态改變時系統會産生一條廣播,接收到這條廣播就能及時地做出提示和儲存資料等操作;當電池電量改變時,系統會産生一條廣播,接收到這條廣播就能在電量低時告知使用者及時儲存進度等等。Android中的廣播機制設計的非常出色,很多事情原本需要開發者親自操作的,現在隻需等待廣播告知自己就可以了,大大減少了開發的工作量和開發周期。而作為應用開發者,就需要數練掌握Android系統提供的一個開發利器,那就是BroadcastReceiver。
在我們詳細分析建立BroadcastReceiver的兩種注冊方式前,我們先羅列本次分析的大綱:
(1)對靜态和動态兩種注冊方式進行概念闡述以及示範實作步驟
(2)簡述兩種BroadcastReceiver的類型(為後續注冊方式的對比做準備)
(3)在預設廣播類型下設定優先級和無優先級情況下兩種注冊方式的比較
(4)在有序廣播類型下兩種注冊方式的比較
(5)通過接受打電話的廣播,在程式(Activity)運作時和終止運作時,對兩種注冊方式的比較
(6)總結兩種方式的特點
第一步:靜态和動态注冊方式基本概念以及實作步驟
建構Intent,使用sendBroadcast方法發出廣播定義一個廣播接收器,該廣播接收器繼承BroadcastReceiver,并且覆寫onReceive()方法來響應事件注冊該廣播接收器,我們可以在代碼中注冊(動态注冊),也可以AndroidManifest.xml配置檔案中注冊(靜态注冊)。
動态注冊:
效果如下圖:

這裡就不示範點選按鈕布局的實作了,MainActivity.java中實作代碼如下:
1 import android.content.BroadcastReceiver;
2 import android.content.Context;
3 import android.content.Intent;
4 import android.content.IntentFilter;
5 import android.support.v7.app.AppCompatActivity;
6 import android.os.Bundle;
7 import android.view.Gravity;
8 import android.view.View;
9 import android.widget.Toast;
10
11 public class MainActivity extends AppCompatActivity {
12 DynamicReceiver dynamicReceiver;
13 @Override
14 protected void onCreate(Bundle savedInstanceState) {
15 super.onCreate(savedInstanceState);
16 setContentView(R.layout.activity_main);
17 //執行個體化IntentFilter對象
18 IntentFilter filter = new IntentFilter();
19 filter.addAction("panhouye");
20 dynamicReceiver = new DynamicReceiver();
21 //注冊廣播接收
22 registerReceiver(dynamicReceiver,filter);
23 }
24 //按鈕點選事件
25 public void send2(View v){
26 Intent intent = new Intent();
27 intent.setAction("panhouye");
28 intent.putExtra("sele","潘侯爺");
29 sendBroadcast(intent);
30 }
31 /*動态注冊需在Acticity生命周期onPause通過
32 *unregisterReceiver()方法移除廣播接收器,
33 * 優化記憶體空間,避免記憶體溢出
34 */
35 @Override
36 protected void onPause() {
37 super.onPause();
38 unregisterReceiver(new MyReceiver());
39 }
40 //通過繼承 BroadcastReceiver建立動态廣播接收器
41 class DynamicReceiver extends BroadcastReceiver{
42 @Override
43 public void onReceive(Context context, Intent intent) {
44 //通過土司驗證接收到廣播
45 Toast t = Toast.makeText(context,"動态廣播:"+ intent.getStringExtra("sele"), Toast.LENGTH_SHORT);
46 t.setGravity(Gravity.TOP,0,0);//友善錄屏,将土司設定在螢幕頂端
47 t.show();
48 }
49 }
50 }
建立方法代碼中做了詳細注釋,有不明白的地方請留言讨論。
靜态注冊:
效果如下:
靜态注冊建立第一步,建立BroadcastReceiver,見下圖:
通過以上步驟,生成MyReceiver.java檔案:
1 import android.content.BroadcastReceiver;
2 import android.content.Context;
3 import android.content.Intent;
4 import android.view.Gravity;
5 import android.widget.Toast;
6
7 public class MyReceiver extends BroadcastReceiver {
8 public MyReceiver() {
9 }
10 @Override
11 public void onReceive(Context context, Intent intent) {
12 Toast t = Toast.makeText(context,"靜态廣播:"+intent.getStringExtra("info"), Toast.LENGTH_SHORT);
13 t.setGravity(Gravity.TOP,0,0);
14 t.show();
15 }
16 }
生成MyReceiver.java的同時,修改AndroidMainfest.xml配置檔案中的代碼:
1 <?xml version="1.0" encoding="utf-8"?>
2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3 package="com.example.administrator.day19">
4 <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
5 <application
6 android:allowBackup="true"
7 android:icon="@mipmap/ic_launcher"
8 android:label="@string/app_name"
9 android:supportsRtl="true"
10 android:theme="@style/AppTheme">
11 <activity android:name=".MainActivity">
12 <intent-filter>
13 <action android:name="android.intent.action.MAIN" />
14
15 <category android:name="android.intent.category.LAUNCHER" />
16 </intent-filter>
17 </activity>
18 //生成的receiver配置檔案
19 <receiver
20 android:name=".MyReceiver"
21 android:enabled="true"
22 android:exported="true">
23 <intent-filter>
24 //自定義Action
25 <action android:name="MLY" />
26 </intent-filter>
27 </receiver>
28 </application>
29 </manifest>
最後在MainActivity.java檔案中添加按鈕點選事件,如下:
1 import android.content.BroadcastReceiver;
2 import android.content.Context;
3 import android.content.Intent;
4 import android.content.IntentFilter;
5 import android.support.v7.app.AppCompatActivity;
6 import android.os.Bundle;
7 import android.view.Gravity;
8 import android.view.View;
9 import android.widget.Toast;
10
11 public class MainActivity extends AppCompatActivity {
12 DynamicReceiver dynamicReceiver;
13 @Override
14 protected void onCreate(Bundle savedInstanceState) {
15 super.onCreate(savedInstanceState);
16 setContentView(R.layout.activity_main);
17 }
18 //靜态廣播點選
19 public void send(View v){
20 Intent intent = new Intent();
21 intent.setAction("MLY");
22 intent.putExtra("info","panhouye");
23 sendBroadcast(intent);
24 }
25 }
至此,兩種注冊方式的實作代碼示範完畢,歡迎探讨。
第二步:為友善後續分析,這裡插入BroadcastReceiver的兩種常用類型
(1)Normalbroadcasts:預設廣播
發送一個預設廣播使用Context.sendBroadcast()方法,普通廣播對于多個接收者來說是完全異步的,通常每個接收者都無需等待即可以接收到廣播,接收者互相之間不會有影響。對于這種廣播,接收者無法終止廣播,即無法阻止其他接收者的接收動作。
(2)orderedbroadcasts:有序廣播
發送一個有序廣播使用Context.sendorderedBroadcast()方法,有序廣播比較特殊,它每次隻發送到優先級較高的接收者那裡,然後由優先級高的接受者再傳播到優先級低的接收者那裡,優先級高的接收者有能力終止這個廣播。
發送有序廣播:sendorderedBroadCast()
在注冊廣播中的<intent-filter>中使用android:priority屬性。這個屬性的範圍在-1000到1000,數值越大,優先級越高。在廣播接收器中使用setResultExtras方法将一個Bundle對象設定為結果集對象,傳遞到下一個接收者那裡,這樣優先級低的接收者可以用getResuttExtras擷取到最新的經過處理的資訊集合。使用sendorderedBroadcast方法發送有序廣播時,需要一個權限參數,如果為null則表示不要求接收者聲明指定的權限,如果不為null則表示接收者若要接收此廣播,需聲明指定權限。這樣做是從安全角度考慮的,例如系統的短信就是有序廣播的形式,一個應用可能是具有攔截垃圾短信的功能,當短信到來時它可以先接受到短信廣播,必要時終止廣播傳遞,這樣的軟體就必須聲明接收短信的權限。
第三步:在預設廣播下兩種注冊方式的比較
(1)兩種注冊方式均不設定優先級
這裡将動态與靜态兩種注冊的廣播觸發集中在一個按鈕上,顯示效果如下(未設定優先級的情況下,先動态後靜态):
這裡同樣不示範按鈕布局檔案,以及靜态注冊涉及AndroidMainfest.xml和MyReceiver.java檔案。直接展示MainActicity.java的實作代碼:
1 import android.content.BroadcastReceiver;
2 import android.content.Context;
3 import android.content.Intent;
4 import android.content.IntentFilter;
5 import android.support.v7.app.AppCompatActivity;
6 import android.os.Bundle;
7 import android.view.Gravity;
8 import android.view.View;
9 import android.widget.Toast;
10
11 public class MainActivity extends AppCompatActivity {
12 DynamicReceiver dynamicReceiver;
13 @Override
14 protected void onCreate(Bundle savedInstanceState) {
15 super.onCreate(savedInstanceState);
16 setContentView(R.layout.activity_main);
17 IntentFilter filter = new IntentFilter();
18 filter.addAction("panhouye");
19 dynamicReceiver = new DynamicReceiver();
20 registerReceiver(dynamicReceiver,filter);
21 }
22 //靜态廣播點選
23 public void send(View v){
24 Intent intent = new Intent();
25 //設定與動态相同的Action,友善同時觸發靜态與動态
26 intent.setAction("panhouye");
27 intent.putExtra("info","潘侯爺");
28 sendBroadcast(intent);//預設廣播
29 }
30 @Override
31 protected void onPause() {
32 super.onPause();
33 unregisterReceiver(new MyReceiver());
34 }
35 class DynamicReceiver extends BroadcastReceiver{
36 @Override
37 public void onReceive(Context context, Intent intent) {
38 Toast t = Toast.makeText(context,"動态廣播:"+ intent.getStringExtra("info"), Toast.LENGTH_SHORT);
39 t.setGravity(Gravity.TOP,0,0);
40 t.show();
41 }
42 }
43 }
(2)将動态優先級設定為最低-1000,靜态優先級設定為最高1000
顯示效果如下(動态仍先于靜态被接收到):
MainActivity中動态優先級設定如下:
1 protected void onCreate(Bundle savedInstanceState) {
2 super.onCreate(savedInstanceState);
3 setContentView(R.layout.activity_main);
4 IntentFilter filter = new IntentFilter();
5 filter.addAction("panhouye");
6 filter.setPriority(-1000);//設定動态優先級
7 dynamicReceiver = new DynamicReceiver();
8 registerReceiver(dynamicReceiver,filter);
9 }
AndroidMainfest.xml中靜态優先級設定如下:
1 <receiver
2 android:name=".MyReceiver"
3 android:enabled="true"
4 android:exported="true">
5 //設定靜态優先級
6 <intent-filter android:priority="1000">
7 <action android:name="panhouye" />
8 </intent-filter>
9 </receiver>
第四步:在有序廣播下兩種注冊方式比較
靜态廣播1(優先級為200),靜态廣播2(優先級為300),靜态廣播3(優先級為400),靜态廣播優先級為(-100),動态廣播優先級為0。顯示效果如下:
出現順序由優先級決定,由高到低分别為靜态3-靜态2-靜态1-動-靜态。(這裡參照前文代碼)
第五步:接受打電話的廣播,比較程式運作中與結束運作時,兩種注冊方式的比較
本次比較采用比對Log的方式對兩種注冊方式進行比較,在MainActivity.java中會插入Activity全部生命周期用于檢測Log分析。
AndroidMainfest.xml配置檔案代碼如下:
1 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2 package="com.example.administrator.test19">
3 //添加撥打電話權限
4 <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
5 <application
6 android:allowBackup="true"
7 android:icon="@mipmap/ic_launcher"
8 android:label="@string/app_name"
9 android:supportsRtl="true"
10 android:theme="@style/AppTheme">
11 <activity android:name=".MainActivity">
12 <intent-filter>
13 <action android:name="android.intent.action.MAIN" />
14
15 <category android:name="android.intent.category.LAUNCHER" />
16 </intent-filter>
17 </activity>
18 <receiver
19 android:name=".StaticReceiver"
20 android:enabled="true"
21 android:exported="true">
22 <intent-filter>
23 //設定打電話對應的action
24 <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
25 </intent-filter>
26 </receiver>
27 </application>
28 </manifest>
MainActivity.java中實作代碼(動态注冊将解除注冊放在onDestory方法内是因為在真機測試過程中撥打電話,需要傳回首頁面,而此操作會造成Activity處于onStop狀态,若放在onPause中,将無法在程式運作時啟用動态注冊接受廣播。真實環境下建議在onpause下解除注冊,盡早釋放記憶體,避免記憶體溢出):
1 import android.content.BroadcastReceiver;
2 import android.content.Context;
3 import android.content.Intent;
4 import android.content.IntentFilter;
5 import android.support.v7.app.AppCompatActivity;
6 import android.os.Bundle;
7 import android.util.Log;
8
9 public class MainActivity extends AppCompatActivity {
10 DynamicReceiver dynamicReceiver;//聲明動态注冊廣播接收
11 @Override
12 protected void onCreate(Bundle savedInstanceState) {
13 super.onCreate(savedInstanceState);
14 setContentView(R.layout.activity_main);
15 IntentFilter filter = new IntentFilter();
16 filter.addAction("android.intent.action.NEW_OUTGOING_CALL");
17 dynamicReceiver = new DynamicReceiver();
18 registerReceiver(dynamicReceiver,filter);
19 Log.i("Tag","Activity-onCreate");
20 }
21 @Override
22 protected void onStart() {
23 super.onStart();
24 Log.i("Tag","Activity-onStart");
25 }
26 @Override
27 protected void onResume() {
28 super.onResume();
29 Log.i("Tag","Activity-onResume");
30 }
31 @Override
32 protected void onPause() {
33 super.onPause();
34 Log.i("Tag","Activity-onPause");
35 }
36 @Override
37 protected void onStop() {
38 super.onPause();
39 Log.i("Tag","Activity-onStop");
40 }
41 @Override
42 protected void onDestroy() {
43 super.onDestroy();
44 Log.i("Tag","Activity-onDestroy");
45 unregisterReceiver(dynamicReceiver);
46 }
47 class DynamicReceiver extends BroadcastReceiver{
48 @Override
49 public void onReceive(Context context, Intent intent) {
50 Log.i("Tag","動态注冊廣播接收到您正在撥打電話"+getResultData());
51 }
52 }
53 }
StaticReceiver.java中實作代碼:
1 import android.content.BroadcastReceiver;
2 import android.content.Context;
3 import android.content.Intent;
4 import android.util.Log;
5 public class StaticReceiver extends BroadcastReceiver {
6 public StaticReceiver() {
7 }
8 @Override
9 public void onReceive(Context context, Intent intent) {
10 Log.i("Tag","靜态注冊廣播接收到您正在撥打電話"+getResultData());
11 }
12 }
(1)在未退出Activity時,撥打電話,Log如下:
由Log可知在未退出Activity是,兩種方式均可接受到廣播。
(2)在退出Activity時,撥打電話,Log如下(即便不解除注冊,動态仍無法接受到廣播):
在退出程式(Activity)時,隻有靜态注冊方式可以接受到廣播。
第六步:總結兩種注冊方式特點
廣播接收器注冊一共有兩種形式:靜态注冊和動态注冊.
兩者及其接收廣播的差別:
(1)動态注冊廣播不是常駐型廣播,也就是說廣播跟随Activity的生命周期。注意在Activity結束前,移除廣播接收器。
靜态注冊是常駐型,也就是說當應用程式關閉後,如果有資訊廣播來,程式也會被系統調用自動運作。
(2)當廣播為有序廣播時:優先級高的先接收(不分靜态和動态)。同優先級的廣播接收器,動态優先于靜态