⑴ 為什麼android要使用各種BroadcastReceiver
作為Android四大組件之一的BroadcastReceiver(廣播接收者),同Activity(活動)一樣,經常被大家用到,網上也是一堆對它的講解,那麼為什麼Android要用廣播接收者這種機制呢?
廣播分為:普通廣播和有序廣播
1.Normal broadcasts(普通廣播):Normal broadcasts是完全非同步的可以同一時間被所有的接收者接收到。消息的傳遞效率比較高。但缺點是接收者不能將接收的消息的處理信息傳遞給下一個接收者也不能停止消息的傳播。可以利用Context.sendBroadcast發送。
2.Ordered broadcasts(有序廣播):Ordered broadcasts的接收者按照一定的優先順序進行消息的接收。一次傳送到一個接收器。 隨著每個接收器依次執行,它可以將結果傳播到下一個接收器,或者它可以完全中止廣播,使得它不會被傳遞到其他接收器。 命令接收器運行可以用匹配的意圖過濾器的android:priority屬性控制; 具有相同優先順序的接收器將以任意順序運行。可以利用Context.sendOrderedBroadcast發送。
官網上介紹廣播是用的監聽系統網路狀況的例子,其實關鍵字在於「監聽」。
(1) 創建廣播接收者
BroadcastReceiver是一個抽象類,所以我們要創建自己的廣播接收者就要繼承它,繼承後會有提示重寫onReceive方法。
public class NetworkBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = manager.getActiveNetworkInfo();
if (activeNetwork != null && activeNetwork.isAvailable()) {
Toast.makeText(context, "有網路連接", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "無網路連接", Toast.LENGTH_SHORT).show();
}
}
}
}
廣播接收者的生命周期是從接收廣播開始,到onRecevier方法執行完成結束,時間很短,一般不允許處理大批量耗時操作。這里順便給出列印NetworkInfo的信息以供參考:
NetworkInfo:
type: WIFI[,type_ext: WIFI],
state: CONNECTED/CONNECTED,
reason: (unspecified),
extra: "TP-LINK_EFE8",
roaming: false,
failover: false,
isAvailable: true,
: false,
isIpv4Connected: true,
isIpv6Connected: false
[type: MOBILE[LTE],
state: CONNECTED/CONNECTED,
reason: connected,
extra: cmnet,
roaming: false,
failover: false,
isAvailable: true,
: false]
(2) 靜態注冊廣播
靜態注冊廣播,需要在AndroidManifest.xml中,添加<recevier/> 標簽,將廣播接收者注冊到應用中。要添加過濾器IntentFilter,由於系統網路變化時會發送ConnectivityManager.CONNECTIVITY_ACTION ("android.net.conn.CONNECTIVITY_CHANGE")的廣播,所以我們要監聽這條廣播。
<receiver android:name=".NetworkBroadcastReceiver">
<intent-filter android:priority="1000">
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
這里priority代表的是執行順序的優先順序,取值[-1000,1000],後面的有序廣播會講到。
(3) 動態注冊廣播
i.意圖過濾器 IntentFilter 用於給BroadcastReceiver綁定監聽廣播類型
ii.自定義的BroadcastReceiver,例如上文的
iii.注冊方法 Context.registerReceiver(Receiver, IntentFilter)
iv.反注冊方法 unregisterReceiver(Receiver)
IntentFilter mFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
mReceiver = new ();
registerReceiver(mReceiver, mFilter);
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
}
這段代碼是成對出現的,可以在onCreate的時候注冊,在onDestroy的時候反注冊,也可以在onResume和onPause中執行這寫方法。不過Google API推薦的做法,在activity的onResume()中注冊,在onPause()反注冊。效果是當界面pause時,就不接收廣播,從而減少不必要的系統開銷。還有就是一定要主動反注冊你的廣播,否則會出現異常。
動態注冊和靜態注冊的差別:動態注冊後,廣播接收者會依賴Activity的生命周期,而靜態注冊的廣播不會,只要是系統有發出的廣播,它都會接收,與程序是否啟動無關。
(4) 發送普通廣播
具體使用的方法是sendBroadcast(Intent intent),通過隱式調用就可以,注意action是你自定義的,意思就是不可以發送系統廣播,我試了,直接就崩了。
Intent intent = new Intent();
intent.setAction("com.fleming.chen.mybroadcast");
sendBroadcast(intent);
針對(3)(4)兩點,如果你要用到的廣播僅僅是應用里的,那麼你可以用LocalBroadcastManager這個類,它與上述描述中的區別在於:
LocalBroadcastManager.getInstance(context).registerReceiver(mReceiver, mFilter);
LocalBroadcastManager.getInstance(context).unregisterReceiver(mReceiver);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
通過sendBroadcast發送的廣播,不會被通過LocalBroadcastManager類注冊的廣播接收者接收,反之也是如此,兩者是不可以」互通友誼「的,推薦使用LocalBroadcastManager來管理廣播。
(5) 發送有序廣播
上面講了那麼多都是普通廣播,那什麼又是有序廣播呢?
有序廣播關鍵在於這類廣播是有序的,上文中提到priority,這是IntentFilter的屬性,用來讓不同的廣播擁有不同的執行順序,即優先順序不同。
定義三種不同優先順序的廣播接收者:
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("com.fleming.chen.myreceiver")) {
String message = getResultData();
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
setResultData("這是修改後的數據");//第一個接收後處理一下,再交給下一個
}
}
}
public class MyBroadcastReceiver2 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("com.fleming.chen.myreceiver")) {
String message = getResultData();//得到上一個的處理結果
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
abortBroadcast();//主動停止廣播,不再繼續傳下去
}
}
}
public class MyBroadcastReceiver3 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("com.fleming.chen.myreceiver")) {
//此時雖然該廣播接收者也監聽了,不過也沒有內容
Toast.makeText(context, getResultData(), Toast.LENGTH_SHORT).show();
}
}
}
<receiver android:name=".MyBroadcastReceiver" >
<intent-filter android:priority="1000">
<action android:name="com.fleming.chen.myreceiver"/>
</intent-filter>
</receiver>
<receiver android:name=".MyBroadcastReceiver2">
<intent-filter android:priority="0">
<action android:name="com.fleming.chen.myreceiver"/>
</intent-filter>
</receiver>
<receiver android:name=".MyBroadcastReceiver3">
<intent-filter android:priority="-1000">
<action android:name="com.fleming.chen.myreceiver"/>
</intent-filter>
</receiver>
Intent intent = new Intent();
intent.setAction("com.fleming.chen.myreceiver");
sendOrderedBroadcast(intent, null, null, null, 0, "這是初始的數據", null);
對於廣播的內容,在Android 7.0上做了修改,即Project Svelte:後台優化
Android 7.0 移除了三項隱式廣播,以幫助優化內存使用和電量消耗。此項變更很有必要,因為隱式廣播會在後台頻繁啟動已注冊偵聽這些廣播的應用。刪除這些廣播可以顯著提升設備性能和用戶體驗。
移動設備會經歷頻繁的連接變更,例如在 WLAN 和移動數據之間切換時。目前,可以通過在應用清單中注冊一個接收器來偵聽隱式 CONNECTIVITY_ACTION 廣播,讓應用能夠監控這些變更。由於很多應用會注冊接收此廣播,因此單次網路切換即會導致所有應用被喚醒並同時處理此廣播。
同理,在之前版本的 Android 中,應用可以注冊接收來自其他應用(例如相機)的隱式 ACTION_NEW_PICTURE 和 ACTION_NEW_VIDEO 廣播。當用戶使用相機應用拍攝照片時,這些應用即會被喚醒以處理廣播。
為緩解這些問題,Android 7.0 應用了以下優化措施:
面向 Android 7.0 開發的應用不會收到 CONNECTIVITY_ACTION 廣播,即使它們已有清單條目來請求接受這些事件的通知。在前台運行的應用如果使用 BroadcastReceiver 請求接收通知,則仍可以在主線程中偵聽 CONNECTIVITY_CHANGE。
應用無法發送或接收 ACTION_NEW_PICTURE 或 ACTION_NEW_VIDEO 廣播。此項優化會影響所有應用,而不僅僅是面向 Android 7.0 的應用。
如果您的應用使用任何 intent,您仍需要盡快移除它們的依賴關系,以正確適配 Android 7.0 設備。Android 框架提供多個解決方案來緩解對這些隱式廣播的需求。例如,JobScheler API 提供了一個穩健可靠的機制來安排滿足指定條件(例如連入無限流量網路)時所執行的網路操作。您甚至可以使用 JobScheler 來適應內容提供程序變化。
所以說,在Android的世界,到處都充滿著廣播,就是為了用來監聽手機的各種狀態,給用戶提醒,這是一種很好的用戶體驗,不過任何事情都是如此,廣播也不可以多用哦,
⑵ android廣播機制的廣播機制的三要素
Android廣播機制包含三個基本要素:廣播(Broadcast) - 用於發送廣播;廣播接收器(BroadcastReceiver) - 用於接收廣播;意圖內容(Intent)-用於保存廣播相關信息的媒介。Broadcast是一種廣泛運用的在應用程序之間傳輸信息的機制。而BroadcastReceiver是對發送出來的Broadcast進行過濾接受並響應的一類組件。
⑶ Android中「強制停止」和廣播保活的一個小坑
一直以來,使用廣播進行Android進程的保活就是一種常規的保活方法,本著用事實說話的原則,我做了一個實驗:
我在5台不同品牌的手機上重復了相同的實驗,結果一致。由此,似乎可以得出結論——廣播保活不靠譜。當然如果這個實驗就這么結束了,那也太短了,男人可不能短,接著看。
後來我看到了這篇文章 論Android應用進程長存的可行性 ,作者幾乎介紹了所有已知的進程保活方法,讓我打開眼界,不過引起我注意的其實是下面這段話:
我突然就想到,應用程序管理器中的「強制停止」功能,會不會默認添加了「STOPPED」狀態呢,所以導致廣播失效呢?
於是我又進行了一次實驗:
以上幾步實驗可以表明:
至此得出的結論是:
廣播保活還是比較靠譜的,畢竟一般用戶不會去「強制停止」,雖然我一開始也誤以為是結束其下所有進程的意思。。。
其實「強制停止」的英語是「Force Stop」,如果了解STOPPED狀態的人,可能會立刻就明白這是做什麼用的了。後來我網路「強制停止」的時候,也發現了有人分析過強制停止對廣播的影響。不過如果沒有接觸過STOPPED概念的人,或者沒有在開發中遇到相關的坑的人,可能很難想到「強制停止」其實並不只是殺進程,所以也就不會去網路相關的資料了,可見誤解甚至是一知半解是多麼的可怕。
我們做開發工作的,不但要在遇到問題的時候能夠解決問題,還應該在各個方面多積累,在遇到問題的時候才能能立刻找到方向。總之一句話:多讀書!!!
⑷ Android學習--廣播機制
Android系統中的廣播機制提供了方便、系統級的消息通知功能,有助於實現高效通信。
接收廣播是通過廣播接收器實現的。注冊廣播有兩種方式:靜態注冊和動態注冊。
靜態注冊允許程序在未啟動時接收廣播,注冊方式在AndroidManifest.xml中完成。動態注冊則更靈活,注冊和注銷操作在代碼中完成,程序啟動後即可接收廣播。
接收廣播時,需注意許可權問題,否則程序會崩潰,需在AndroidManifest.xml中聲明相應的訪問許可權。
發送廣播有兩種類型:標准廣播和有序廣播。
標准廣播是非同步執行,接收者幾乎同時接收廣播消息,適用於不涉及順序的全局廣播。有序廣播則是同步執行,一次廣播只有一個接收者處理完,然後繼續傳遞給下一個,適用於需要按順序執行的全局廣播。
標准廣播允許任何應用接收,存在安全風險。為了解決安全問題,Android提供了本地廣播機制,僅限於程序內部傳遞,僅由本應用的廣播接收器接收。
發送標准廣播的代碼示例:定義廣播接收器MyBroadcastReceiver,通過代碼動態注冊,完成廣播發送。發送操作在main_activity.xml中實現,通過MainActivity類調用發送方法。