1.BroadcastReceiver簡介:
BroadcastReceiver 廣播接收器,這個組件本質上就是一種全局監聽器,用於監聽全局廣播(Broadcast)消息,因此它可以非常方便的實現系統不同組件之間的通信。
BroadcastReceiver這個監聽器與普通的onXxxListener監聽器是不同的,onXxxListener是屬於應用程序級別的監聽器,當程序退出的時候那麼這個監聽器也就隨之結束了。而BroadcastReceiver(配置文件中注冊)屬於系統級別的監聽器,它擁有自己的進程,只要存在與之匹配的Broadcast以intent形式傳遞過來,那麼BroadcastReceiver就會被激活。
與Activity不同的是,當系統通過Intent啟動指定的Activity組件時,如果系統沒有找到目標Activity組件,這時就會發生程序異常中斷,但系統通過Intent激活BroadcastReceiver時,即使沒有找到目標BroadcastReceiver時,系統也不會有任何問題
2.創建BroadcastReceiver
2.1 首先需要繼承BroadcastReceiver類,重寫這個類裡面的onReceive()方法,代碼如下:
1 package com.example.administrator.broadcastreceivertest; 2 3 import Android.content.BroadcastReceiver; 4 import android.content.Context; 5 import android.content.Intent; 6 import android.util.Log; 7 import android.widget.Toast; 8 9 10 public class MyBroadcastReceiver extends BroadcastReceiver{ 11 public MyBroadcastReceiver() { 12 Log.i("tag","創建構造器..."); 13 } 14 15 @Override 16 public void onReceive(Context context, Intent intent) { 17 String msg = intent.getStringExtra("msg"); 18 Toast.makeText(context,msg,Toast.LENGTH_SHORT).show(); 19 } 20 }
當一個BroadcastReceiver被激活之後,系統會為之創建一個BroadcastReceiver實例,並自動觸發它的onReceive()方法,onReceive()方法被執行完後,BroadcastReceiver實例就會被銷毀。如果BroadcastReceiver的onReceive()方法不能在10s內執行完成,Android會認為該程序無響應,所以不要在onReceive()方法中執行耗時操作,否則會彈出ANR(Application No Response)對話框。
如果在onReceive()方法中需要執行耗時操作,可以考慮使用Intent啟動一個Service來完成操作,此時不應該考慮啟動一個新的線程去處理耗時操作,因為BroadcastReceiver的生命周期很短,可能子線程還沒有結束,BroadcastReceiver就已經退出了。而如果BroadcastReceiver所在的進程結束了,那麼該線程就會標記為一個空線程。根據Android內存管理策略,在系統內存緊張時,會根據優先級首先結束優先級低的線程,而空線程優先級無疑是擁有最低的優先級,系統回收後,線程就無法完成相關操作了
2.2 注冊BroadcastReceiver
注冊BroadcastReceiver的兩種方式:
1>使用代碼進行指定(動態注冊),調用Context類提供的registerReceiver(BroadcastReceiver receiver,IntentFilter filter);代碼如下
1 MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver(); 2 IntentFilter filter = new IntentFilter(SHOW_MESSAGE); 3 registerReceiver(myBroadcastReceiver,filter);
IntentFilter 是根據SHOW_MESSAGE用來匹配Broadcast的,SHOW_MESSAGE是一個自定義的靜態字符串常量。
要注意的是,BroadcastReceiver注冊的地方,google 官方指出:
Note: If registering a receiver in your Activity.onResume()
implementation, you should unregister it in Activity.onPause()
. (You won't receive intents when paused, and this will cut down on unnecessary system overhead). Do not unregister in Activity.onSaveInstanceState()
, because this won't be called if the user moves back in the history stack.
意思大概是:如果你要在Activity類中的onResume()方法中注冊一個receiver,你也應該在Activity類onPause()方法中取消注冊。不要在onSaveInstanceState()方法中取消注冊,因為如果用戶退出當前Activity(從task中移除Activity)時,那麼這個BroadcastReceiver也將不能被激活。
特點:當應用程序關閉後,就不再監聽。對於我們開發的App來說,越省電就會越受用戶的歡迎,所以對於那些沒有必要在應用程序退出後仍然進行監聽的receiver,在代碼中注冊是一個不錯的選擇
2>在AndroidManifest.xml中注冊(靜態注冊),代碼如下:
1 <receiver android:name=".MyBroadcastReceiver"> 2 <intent-filter> 3 <action android:name="com.example.administrator.broadcastreceiver.SEND_MESSAGE"/> 4 </intent-filter> 5 </receiver>
特點:不管應用程序是否處於活動狀態,都會進行監聽。比如某個應用程序監聽內存使用情況,當在手機上安裝好之後,不管其處於什麼狀態都會監聽內存狀態。
2.3 生命周期
BroadcastReceiver的生命周期很簡單,如下圖
3.Broadcast介紹
3.1Broadcast被分為兩種:
1>Normal Broadcast(普通廣播):
Normal Broadcast是完全異步的,可以在同一時刻,被所有接收者接收到(邏輯上),消息傳遞效率比較高。缺點是接收者不能將結果傳給下一個接收者,並且無法阻止Broadcast Intent的傳播
2>Ordered Broadcast(有序廣播):
Ordered Broadcast的接收者將按照預先聲明的優先級次序依次接收Broadcast。如果priority:A>B>C,那麼Broadcast先傳給A->B->C。
3.2 發送廣播的兩種方式:
1>sendBroadcast():發送Normal Broadcast
2>sendOrderedBroadcast():發送Ordered Broadcast
對於Ordered Broadcast而言系統會根據接收者聲明的優先級別按順序依次執行接收者,優先收到Broadcast的接收者可以終止Broadcast(調用BroadcastReceiver的abortBroadcast()方法),那麼後面的接收者將無法取到Broadcast.
不僅如此,對於Ordered Broadcast而言,優先級別高的接收者,可以通過setResultExtras(Bundle bundle)將結果存到Broadcast中,下一個接收者可以通過Bundle bundle = getResultExtras(true)獲取上一個數據
TIP:系統接收短信,發出的Broadcast屬於Ordered Broadcast.如果想攔截用戶收到短信,可以設置優先級,讓自定義的BroadcastReceiver先接收到短信,然後終止broadcast。
4.下面是一個Ordered Broadcast廣播例子,代碼如下:
MainActivity類:
1 package com.example.administrator.broadcastreceivertest; 2 3 import android.app.Activity; 4 import android.content.Intent; 5 import android.os.Bundle; 6 import android.view.View; 7 8 9 public class MainActivity extends Activity { 10 11 private static final String SHOW_MESSAGE = "com.example.administrator.broadcastreceiver.SEND_MESSAGE"; 12 @Override 13 protected void onCreate(Bundle savedInstanceState) { 14 super.onCreate(savedInstanceState); 15 setContentView(R.layout.activity_main); 16 } 17 18 public void sendOrderedBroadcast(View view){ 19 Intent intent = new Intent(SHOW_MESSAGE); 20 intent.putExtra("msg","Ordered Broadcast"); 21 sendOrderedBroadcast(intent,null); 22 } 23 24 }
MyBroadcastReceiver類
1 package com.example.administrator.broadcastreceivertest; 2 3 import android.content.BroadcastReceiver; 4 import android.content.Context; 5 import android.content.Intent; 6 import android.util.Log; 7 import android.widget.Toast; 8 9 10 public class MyBroadcastReceiver extends BroadcastReceiver{ 11 12 @Override 13 public void onReceive(Context context, Intent intent) { 14 String msg = intent.getStringExtra("msg"); 15 Log.i("tag","MyBroadcastReceiver:"+msg); 16 Toast.makeText(context,"MyBroadcastReceiver:"+msg,Toast.LENGTH_SHORT).show(); 17 } 18 }
MyBroadcastReceiver2類
1 package com.example.administrator.broadcastreceivertest; 2 3 import android.content.BroadcastReceiver; 4 import android.content.Context; 5 import android.content.Intent; 6 import android.util.Log; 7 import android.widget.Toast; 8 9 10 public class MyBroadcastReceiver2 extends BroadcastReceiver{ 11 12 @Override 13 public void onReceive(Context context, Intent intent) { 14 String msg = intent.getStringExtra("msg"); 15 Log.i("tag","MyBroadcastReceiver2:"+msg); 16 Toast.makeText(context,"MyBroadcastReceiver2:"+msg,Toast.LENGTH_LONG).show(); 17 } 18 }
activity_main.xml
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" 3 android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" 4 android:paddingRight="@dimen/activity_horizontal_margin" 5 android:paddingTop="@dimen/activity_vertical_margin" 6 android:orientation="vertical" 7 android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> 8 9 10 <Button 11 android:layout_width="wrap_content" 12 android:layout_height="wrap_content" 13 android:text="發送 Ordered Broadcast " 14 android:onClick="sendOrderedBroadcast"/> 15 </LinearLayout>
AndroidManifest.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.broadcastreceivertest" > 4 5 <application 6 android:allowBackup="true" 7 android:icon="@drawable/ic_launcher" 8 android:label="@string/app_name" 9 android:theme="@style/AppTheme" > 10 <activity 11 android:name=".MainActivity" 12 android:label="@string/app_name" > 13 <intent-filter> 14 <action android:name="android.intent.action.MAIN" /> 15 16 <category android:name="android.intent.category.LAUNCHER" /> 17 </intent-filter> 18 </activity> 19 20 21 <receiver android:name=".MyBroadcastReceiver"> 22 <intent-filter android:priority="1"> 23 <action android:name="com.example.administrator.broadcastreceiver.SEND_MESSAGE"/> 24 </intent-filter> 25 </receiver> 26 27 <receiver android:name=".MyBroadcastReceiver2"> 28 <intent-filter android:priority="2"> 29 <action android:name="com.example.administrator.broadcastreceiver.SEND_MESSAGE"/> 30 </intent-filter> 31 </receiver> 32 </application> 33 34 </manifest>
運行結果:
控制台輸出結果:
從運行結果可以看出先是MyBroadcastReceiver2先接收到Broadcast,接著才是MyBroadcastReceiver,因為我在注冊時將MyBroadcastReceiver2的優先級設置為2,MyBroadcastReceiver優先級為1。
更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11