android廣播生命周期
『壹』 為什麼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閲宐roadcast閲岄潰鐨刼nrecive鏂規硶涓嶆柇寰鐜鎵ц屾槸浠涔堟儏鍐
BroadCastReceiver 綆浠 錛堟湯灝炬湁婧愮爜錛
BroadCastReceiver 婧愮爜浣嶄簬錛 framework/base/core/java/android.content.BroadcastReceiver.java
騫挎挱鎺ユ敹鑰咃紙 BroadcastReceiver 錛夌敤浜庢帴鏀跺箍鎾 Intent 錛屽箍鎾 Intent 鐨勫彂閫佹槸閫氳繃璋冪敤Context.sendBroadcast() 銆 Context.sendOrderedBroadcast() 鏉ュ疄鐜扮殑銆傞氬父涓涓騫挎挱 Intent 鍙浠ヨ璁㈤槄浜嗘Intent 鐨勫氫釜騫挎挱鎺ユ敹鑰呮墍鎺ユ敹銆
騫挎挱鏄涓縐嶅箍娉涜繍鐢ㄧ殑鍦ㄥ簲鐢ㄧ▼搴忎箣闂翠紶杈撲俊鎮鐨勬満鍒 銆傝 BroadcastReceiver 鏄瀵瑰彂閫佸嚭鏉ョ殑騫挎挱榪涜岃繃婊ゆ帴鏀跺苟鍝嶅簲鐨勪竴綾葷粍浠訛紱
鏉ヨ嚜鏅閫氬簲鐢ㄧ▼搴忥紝濡備竴涓搴旂敤紼嬪簭閫氱煡鍏朵粬搴旂敤紼嬪簭鏌愪簺鏁版嵁宸茬粡涓嬭澆瀹屾瘯銆
BroadcastReceiver 鑷韜騫朵笉瀹炵幇鍥懼艦鐢ㄦ埛鐣岄潰錛屼絾鏄褰撳畠鏀跺埌鏌愪釜閫氱煡鍚庯紝 BroadcastReceiver 鍙浠ュ惎鍔ˋctivity 浣滀負鍝嶅簲錛屾垨鑰呴氳繃 NotificationMananger 鎻愰啋鐢ㄦ埛錛屾垨鑰呭惎鍔 Service 絳夌瓑銆
BroadCastReceiver 鐨勬満鍒
1. 鏈哄埗
鍦 Android 閲岄潰鏈夊悇縐嶅悇鏍風殑騫挎挱錛屾瘮濡傜數奼犵殑浣跨敤鐘舵侊紝鐢佃瘽鐨勬帴鏀跺拰鐭淇$殑鎺ユ敹閮戒細浜х敓涓涓騫挎挱錛屽簲鐢ㄧ▼搴忓紑鍙戣呬篃鍙浠ョ洃鍚榪欎簺騫挎挱騫跺仛鍑虹▼搴忛昏緫鐨勫勭悊銆傚傚浘錛
2. 瀹炵幇
鐢ㄦ帴鏀剁煭淇′婦渚嬶細
絎涓縐嶆柟寮 錛
瀹炵幇
public class MyBroadcastReceiver extends BroadcastReceiver {
// action 鍚嶇О
String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED" ;
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals( SMS_RECEIVED )) {
// 鐩稿叧澶勭悊 : 鍦板煙鍙樻崲銆佺數閲忎笉瓚熾佹潵鐢墊潵淇★紱
}
}
}
緋葷粺娉ㄥ唽錛氬湪 AndroidManifest.xml 涓娉ㄥ唽
< receiver android:name = ".MyBroadcastReceiver" >
< intent-filter android:priority = "1000" >
< action android:name = " android.provider.Telephony.SMS_RECEIVED" />
</ intent-filter >
</ receiver > 褰撶劧浜嗛渶瑕佹潈闄 錛
< uses-permission android:name = "android.permission.RECEIVE_SMS" />
< uses-permission android:name = "android.permission.SEND_SMS" />
絎浜岀嶆柟寮忥細
// 騫挎挱鎺ユ敹鑰 - 騫挎挱鐨勬帴鏀
private BroadcastReceiver myBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// 鐩稿叧澶勭悊錛屽傛敹鐭淇★紝鐩戝惉鐢甸噺鍙樺寲淇℃伅
}
};
浠g爜涓娉ㄥ唽錛
IntentFilter intentFilter = new IntentFilter( "android.provider.Telephony.SMS_RECEIVED " );
registerReceiver( mBatteryInfoReceiver , intentFilter);
3. 鐢熷懡鍛ㄦ湡
鎻忚堪浜 Android 涓騫挎挱鐨勭敓鍛藉懆鏈燂紝鍏舵″畠騫朵笉鍍 Activity 涓鏍峰嶆潅錛岃繍琛屽師鐞嗗緢綆鍗曞備笅鍥撅細
鐢熷懡鍛ㄦ湡鍙鏈夊嶮縐掑乏鍙籌紝濡傛灉鍦 onReceive() 鍐呭仛瓚呰繃鍗佺掑唴鐨勪簨鎯咃紝灝變細鎶ラ敊 銆
姣忔″箍鎾鍒版潵鏃 , 浼氶噸鏂板壋寤 BroadcastReceiver 瀵硅薄 , 騫朵笖璋冪敤 onReceive() 鏂規硶 , 鎵ц屽畬浠ュ悗 , 璇ュ硅薄鍗寵閿姣 . 褰 onReceive() 鏂規硶鍦 10 縐掑唴娌℃湁鎵ц屽畬姣曪紝 Android 浼氳や負璇ョ▼搴忔棤鍝嶅簲 . 鎵浠ュ湪
BroadcastReceiver 閲屼笉鑳藉仛涓浜涙瘮杈冭楁椂鐨勬搷浣 , 鍚︿晶浼氬脊鍑 ANR(Application No
Response) 鐨勫硅瘽妗 . 銆
『叄』 android廣播機制的廣播的生命周期
廣播接收器僅在它執行這個方法時處於活躍狀態。當onReceive()返回後,它即為失活狀態。
擁有一個活躍狀態的廣播接收器的進程被保護起來而不會被殺死,但僅擁有失活狀態組件的進程則會在其它進程需要它所佔有的內存的時候隨時被殺掉。所以,如果響應一個廣播信息需要很長的一段時間,我們一般會將其納入一個衍生的線程中去完成,而不是在主線程內完成它,從而保證用戶交互過程的流暢。
『肆』 Android闈欐佹敞鍐屽箍鎾鍜屽姩鎬佹敞鍐屽箍鎾鐨勫尯鍒
1.鍔ㄦ佹敞鍐屽箍鎾涓嶆槸甯擱┗鍨嬪箍鎾錛屼篃灝辨槸璇村箍鎾璺熼殢activity鐨勭敓鍛藉懆鏈熴傛敞鎰: 鍦╝ctivity緇撴潫鍓嶏紝縐婚櫎騫挎挱鎺ユ敹鍣ㄣ
闈欐佹敞鍐屾槸甯擱┗鍨嬶紝涔熷氨鏄璇村綋搴旂敤紼嬪簭鍏抽棴鍚庯紝濡傛灉鏈変俊鎮騫挎挱鏉ワ紝紼嬪簭涔熶細琚緋葷粺璋冪敤鑷鍔ㄨ繍琛屻
瀹冪殑鐢熷懡鍛ㄦ湡涓轟粠鍥炶皟onReceive()鏂規硶寮濮嬪埌璇ユ柟娉曡繑鍥炵粨鏋滃悗緇撴潫銆
2.褰撳箍鎾涓烘湁搴忓箍鎾鏃訛細
1 浼樺厛綰ч珮鐨勫厛鎺ユ敹
2 鍚屼紭鍏堢駭鐨勫箍鎾鎺ユ敹鍣錛屽姩鎬佷紭鍏堜簬闈欐
3 鍚屼紭鍏堢駭鐨勫悓綾誨箍鎾鎺ユ敹鍣錛岄潤鎬侊細鍏堟壂鎻忕殑浼樺厛浜庡悗鎵鎻忕殑錛屽姩鎬侊細鍏堟敞鍐岀殑浼樺厛浜庡悗娉ㄥ唽鐨勩
『伍』 android 生命周期 有什麼用
在 Android 中,多數情況下每個程序都是在各自獨立的 Linux 進程中運行的。當一個程序或其某些部分被請求時,它的進程就「出生」了;當這個程序沒有必要再運行下去且系統需要回收這個進程的內存用於其他程序時,這個 進程就「死亡」了。可以看出,Android 程序的生命周期是由系統控制而非程序自身直接控制。這和我們編寫桌面應用程序時的思維有一些不同,一個桌面應用程序的進程也是在其他進程或用戶請求時被創 建,但是往往是在程序自身收到關閉請求後執行一個特定的動作(比如從 main 函數中 return)而導致進程結束的。要想做好某種類型的程序或者某種平台下的程序的開發,最關鍵的就是要弄清楚這種類型的程序或整個平台下的程序的一般工作 模式並熟記在心。在 Android 中,程序的生命周期控制就是屬於這個范疇——我的個人理解:)
在 Android 系統中,當某個 activity調用 startActivity(myIntent) 時,系統會在所有已經安裝的程序中尋找其 intent filter 和 myIntent 最匹配的一個 activity,啟動這個進程,並把這個 intent 通知給這個 activity。這就是一個程序的「生」。比如我們在 Home application 中選擇 「Web browser」,系統會根據這個 intent 找到並啟動 Web browser 程序,顯示 Web browser 的一個 activity 供我們瀏覽網頁(這個啟動過程有點類似我們在在個人電腦上雙擊桌面上的一個圖標,啟動某個應用程序)。在 Android 中,所有的應用程序「生來就是平等的」,所以不光 Android 的核心程序甚至第三方程序也可以發出一個 intent 來啟動另外一個程序中的一個 activity。Android 的這種設計非常有利於「程序部件」的重用。
一個 Android 程序的進程是何時被系統結束的呢?通俗地說,一個即將被系統關閉的程序是系統在內存不足(low memory)時,根據「重要性層次」選出來的「犧牲品」。一個進程的重要性是根據其中運行的部件和部件的狀態決定的。各種進程按照重要性從高到低排列如 下:
1. 前台進程。這樣的進程擁有一個在屏幕上顯示並和用戶交互的 activity 或者它的一個IntentReciver 正在運行。這樣的程序重要性最高,只有在系統內存非常低,萬不得已時才會被結束。
2. 可見進程。在屏幕上顯示,但是不在前台的程序。比如一個前台進程以對話框的形式顯示在該進程前面。這樣的進程也很重要,它們只有在系統沒有足夠內存運行所有前台進程時,才會被結束。
3. 服務進程。這樣的進程在後台持續運行,比如後台音樂播放、後台數據上傳下載等。這樣的進程對用戶來說一般很有用,所以只有當系統沒有足夠內存來維持所有的前台和可見進程時,才會被結束。
4. 後台進程。這樣的程序擁有一個用戶不可見的 activity。這樣的程序在系統內存不足時,按照 LRU 的順序被結束。
5. 空進程。這樣的進程不包含任何活動的程序部件。系統可能隨時關閉這類進程。
從某種意義上講,垃圾收集機制把程序員從「內存管理噩夢」中解放出來,而 Android 的進程生命周期管理機制把用戶從「任務管理噩夢」中解放出來。我見過一些 Nokia S60 用戶和 Windows Mobile 用戶要麼因為長期不關閉多餘的應用程序而導致系統變慢,要麼因為不時查看應用程序列表而影響使用體驗。Android 使用 Java 作為應用程序 API,並且結合其獨特的生命周期管理機制同時為開發者和使用者提供最大程度的便利。