今天我們一起來探討下安卓中BroadcastReceiver組件以及詳細分析下它的兩種註冊方式。 BroadcastReceiver也就是“廣播接收者”的意思,顧名思義,它就是用來接收來自系統和應用中的廣播。在Android系統中,廣播體現在方方面面,例如當開機完成後系統會產生一條廣播,接收到這條廣 ...
今天我們一起來探討下安卓中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)當廣播為有序廣播時:優先順序高的先接收(不分靜態和動態)。同優先順序的廣播接收器,動態優先於靜態
(3)同優先順序的同類廣播接收器,靜態:先掃描的優先於後掃描的,動態:先註冊的優先於後註冊的。
(4)當廣播為預設廣播時:無視優先順序,動態廣播接收器優先於靜態廣播接收器。同優先順序的同類廣播接收器,靜態:先掃描的優先於後掃描的,動態:先註冊的優先於後冊的。