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,并且结合其独特的生命周期管理机制同时为开发者和使用者提供最大程度的便利。