Android元件- 廣播的靜態動態有序無序與優先順序
設計模式中有一種比較常用的模式——觀察者模式:觀察者模式定義了一種一對多的依賴關係,讓多個觀察者物件同時接收某一個主題物件的訊息。這個主題物件在狀態發生變化時,會通知所有觀察者物件,使它們能夠自動更新自己。Android中的廣播接收器,就是觀察者模式經典的案例,基於對觀察者模式的理解,我們也應當對BroadcastReceiver的優缺點有個基本認識。
優點:廣播發送者與接收者的耦合度很低,可以非常便利的解耦重構接收者的業務邏輯,解除耦合關係。
缺點:如果廣播發送者有很多的接收者的話,要通知到所有的接收者需要一定的時間。
對BroadcastReceiver的設計思想有了一定了解之後,我們再來看Android BroadcastReceiver的一些關鍵知識點:
一. 普通(無序)廣播和有序廣播
1. 普通(無序)廣播: 所有接收器都是非同步處理的,所有註冊的廣播接收器在同一時間(理論上~)收到廣播訊息,收到的訊息都是一致的,互相不能改變廣播訊息,也不能終止廣播的傳送。
2. 有序廣播:做為對立面,可以想象普通廣播不能做的,在這裡可以做。
a). 廣播訊息是按照註冊接收器時宣告的優先順序,按順序發給各個接收器的,優先順序最大可以宣告為int型的最大值,也就是2147483647(為了最高優先順序,拼了)。
b). 優先收到廣播的接收者,可以改變訊息的內容,將自己的處理結果發給下一個接收者。當然,也可以直接中斷這個廣播,後面的接收者就無法接收了。
有人就有江湖,有優先順序就有競爭,一個典型的案例就是市場上各個通訊錄產品,比如QQ,91通訊錄,為什麼他們可以攔截系統簡訊,把新的簡訊放到自己的庫裡面呢?其實原理很簡單,就是有序廣播。Android系統的簡訊是通過有序廣播發送的,系統原生的簡訊app也是通過註冊BroadcastReceiver來處理簡訊,因此我們只要在註冊一個簡訊接收器,把優先順序調到最最高的2147483647(QQ,91們估計就是這麼幹的),就能在系統原生的簡訊app之前,接收到簡訊廣播,接下來愛幹嘛幹嘛了。
好奇的同學估計會問,都是2147483647,順序是怎樣的呢?答,誰先註冊,誰先呼叫。
好奇的同學估計還會問,都是2147483647,有沒可能都是我註冊的先呼叫?答,有可能,通過動態註冊!因為相同優先順序的廣播接收器,動態註冊的會排在靜態註冊的前面。
接下來,就讓我們來看第二個關鍵知識點。
二. 靜態廣播和動態廣播
1. 先說明下,這裡把靜態註冊的廣播簡稱為靜態廣播,動態註冊的廣播簡稱為動態廣播。
靜態註冊是通過AndroidManifest的標籤<receiver>來實現的:
動態廣播則是通過程式碼來註冊的:<receiver android:name="com.yourapp.demoReceiver"> <intent-filter> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> </intent-filter> </receiver>
public class BrocastReceiverDemo extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
this.registerReceiver(connectChangedReceiver, filter);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (connectChangedReceiver != null)
this.unregisterReceiver(connectChangedReceiver);
}
BroadcastReceiver connectChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//doSomething();
}
};
}
2. 動態廣播能做的,靜態廣播也能做,但是反過來就不成立了,接下來就一起看看靜態廣播有哪些特性。
a). 靜態廣播不依賴於應用的程序,換句話說就是即使我們的應用沒開啟,也可以接收廣播。市場上一大票開機自啟動的應用,就是註冊了手機的開機廣播來實現的。
b). 靜態廣播可以增加android:exported="false"
的設定,限制只能接收本應用的廣播訊息。注意,加了android:exported="false"
,系統的廣播也接收不到了。
c). 關於a中說明的特性,在4.X系統中有一個bug,如果我們的app在安裝過後從未啟動,靜態廣播不會生效。雖然網上貼有一些特殊的方法來解決,但還是有ROM的適配問題(有興趣的同學可以自行百度,關鍵字intent.setFlags(32)
)。
三. 廣播接收器的其他要點
1. BroadcastReceiver.onReceive預設是在主執行緒(UI執行緒)執行的,這也是老生常談的“千萬不能在廣播接收器做耗時操作,會ANR!”的真正原因。
2. 廣播發送者可以指定接收廣播的應用,只要將sendBroadcast(intent)的intent加上具體的包名就行了,intent.setPackage("yourpackagename")。
3. 廣播發送者和接收者都可以宣告許可權,這樣只有在AndroidManifest宣告對應許可權,才能接收到相應的廣播訊息。