簡介
BroadcastReceiver 用于異步接收廣播Intent。主要有兩大類,用于接收廣播的:
- 正常廣播 Normal broadcasts(用 Context.sendBroadcast()發送)是完全異步的。它們都運行在一個未定義的順序,通常是在同一時間。這樣會更有效,但意味著receiver不能包含所要使用的結果或中止的API。
- 有序廣播 Ordered broadcasts(用 Context.sendOrderedBroadcast()發送)每次被發送到一個receiver。所謂有序,就是每個receiver執行后可以傳播到下一個receiver,也可以完全中止傳播--不傳播給其他receiver。 而receiver運行的順序可以通過matched intent-filter 里面的android:priority來控制,當priority優先級相同的時候,Receiver以任意的順序運行。
要注意的是,即使是Normal broadcasts,系統在某些情況下可能會恢復到一次傳播給一個receiver。 特別是receiver可能需要創建一個進程,為了避免系統超載,只能一次運行一個receiver。
Broadcast Receiver 并沒有提供可視化的界面來顯示廣播信息。可以使用Notification和Notification Manager來實現可視化的信息的界面,顯示廣播信息的內容,圖標及震動信息。
生命周期
一個BroadcastReceiver 對象只有在被調用onReceive(Context, Intent)的才有效的,當從該函數返回后,該對象就無效的了,結束生命周期。
因此從這個特征可以看出,在所調用的onReceive(Context, Intent)函數里,不能有過于耗時的操作,不能使用線程來執行。因為當得到其他異步操作所返回的結果時,BroadcastReceiver 可能已經無效了。
發送廣播
事件的廣播比較簡單,構建Intent對象,可調用sendBroadcast(Intent)方法將廣播發出。
- 創建一個Intent
Intent intent = new Intent(String action);
- setDate等準備好之后,發送廣播
sendBroadcast(Intent);
接受廣播
自定義廣播接收器需要繼承基類BroadcastReceivre,并實現抽象方法onReceive(context, intent)方法。廣播接收器接收到相應廣播后,會自動回到onReceive(..)方法。默認情況下,廣播接收器也是運行在UI線程,因此,onReceive方法中不能執行太耗時的操作。否則將因此ANR。一般情況下,根據實際業務需求,onReceive方法中都會涉及到與其他組件之間的交互,如發送Notification、啟動service等。
下面代碼片段是一個簡單的廣播接收器的自定義:
public class MyBroadcastReceiver extends BroadcastReceiver {
public static final String TAG = "MyBroadcastReceiver";
public static int m = 1;
@Override
public void onReceive(Context context, Intent intent) {
Log.w(TAG, "intent:" + intent);
String name = intent.getStringExtra("name");
Log.w(TAG, "name:" + name + " m=" + m);
m++;
Bundle bundle = intent.getExtras();
}
}
BroadcastReceiver注冊類型
BroadcastReceiver總體上可以分為兩種注冊類型:靜態注冊和動態注冊。
- 靜態注冊
直接在AndroidManifest.xml文件中進行注冊。規則如下:
<receiver
android:enabled=["true" | "false"]
android:exported=["true" | "false"]
android:icon="drawable resource"
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string" >
. . .
</receiver>
android:exported ——此broadcastReceiver能否接收其他App的發出的廣播,這個屬性默認值有點意思,其默認值是由receiver中有無intent-filter決定的,如果有intent-filter,默認值為true,否則為false。
android:name —— 此broadcastReceiver類名;
android:permission ——如果設置,具有相應權限的廣播發送方發送的廣播才能被此broadcastReceiver所接收;
android:process ——broadcastReceiver運行所處的進程。默認為app的進程。可以指定獨立的進程(Android四大基本組件都可以通過此屬性指定自己的獨立進程)
常見的注冊形式有:
<receiver android:name=".MyBroadcastReceiver" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
其中,intent-filter由于指定此廣播接收器將用于接收特定的廣播類型。本示例中給出的是用于接收網絡狀態改變或開啟啟動時系統自身所發出的廣播。當此App首次啟動時,系統會自動實例化MyBroadcastReceiver,并注冊到系統中。
- 動態注冊
動態注冊時,無須在AndroidManifest中注冊<receiver/>組件。直接在代碼中通過調用Context的registerReceiver函數,可以在程序中動態注冊BroadcastReceiver。registerReceiver的定義形式如下:
registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler)
典型的寫法示例如下:
public class MainActivity extends Activity {
public static final String BROADCAST_ACTION = "com.example.corn";
private BroadcastReceiver mBroadcastReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBroadcastReceiver = new MyBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BROADCAST_ACTION);
registerReceiver(mBroadcastReceiver, intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mBroadcastReceiver);
}
}
其他廣播
- System Broadcast: 系統廣播
Android系統中內置了多個系統廣播,只要涉及到手機的基本操作,基本上都會發出相應的系統廣播。如:開啟啟動,網絡狀態改變,拍照,屏幕關閉與開啟,點亮不足等等。每個系統廣播都具有特定的intent-filter,其中主要包括具體的action,系統廣播發出后,將被相應的BroadcastReceiver接收。系統廣播在系統內部當特定事件發生時,有系統自動發出。 - Sticky Broadcast:粘性廣播(在 android 5.0/api 21中deprecated,不再推薦使用,相應的還有粘性有序廣播,同樣已經deprecated)。
既然已經deprecated,此處不再多做總結。 - Local Broadcast:App應用內廣播(此處的App應用以App應用進程為界)
由前文闡述可知,Android中的廣播可以跨進程甚至跨App直接通信,且注冊是exported對于有intent-filter的情況下默認值是true,由此將可能出現安全隱患如下:
1.其他App可能會針對性的發出與當前App intent-filter相匹配的廣播,由此導致當前App不斷接收到廣播并處理;
2.其他App可以注冊與當前App一致的intent-filter用于接收廣播,獲取廣播具體信息。
App應用內廣播可以理解成一種局部廣播的形式,廣播的發送者和接收者都同屬于一個App。實際的業務需求中,App應用內廣播確實可能需要用到。同時,之所以使用應用內廣播時,而不是使用全局廣播的形式,更多的考慮到的是Android廣播機制中的安全性問題。
為此,Android v4兼容包中給出了封裝好的LocalBroadcastManager類,用于統一處理App應用內的廣播問題,使用方式上與通常的全局廣播幾乎相同,只是注冊/取消注冊廣播接收器和發送廣播時將主調context變成了LocalBroadcastManager的單一實例。
代碼片段如下:
//注冊應用內廣播接收器
localBroadcastManager = LocalBroadcastManager.getInstance(this);
localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);
//取消注冊應用內廣播接收器
localBroadcastManager.unregisterReceiver(mBroadcastReceiver);
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION);
intent.putExtra("name", "qqyumidi");
//發送應用內廣播
localBroadcastManager.sendBroadcast(intent);