第一篇文。
一、官方文档翻译
原文链接(请科学上网 _ )
BroadcastReceiver是一个用于接收从sendBroadcast()发出的intent意图的基础类。
如果你不需要通过应用发送广播,那么请考虑使用LocalBroadcastManager来代替下面将介绍的更加通用的方法与此类结合使用。这将会使你的代码更加高效(没有跨进程交流的需求)并且让你无需考虑有关其他应用能够接收和发送你的广播所产生的安全问题。
你可以通过 [Context.registerReceiver()](https://developer.android.com/reference/android/content/Context.html#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter))动态注册BroadcastReceiver或者在AndroidManifest.xml中通过 [<receiver>]
(https://developer.android.com/reference/android/R.styleable.html#AndroidManifestReceiver)标签静态注册。
注意:如果你在 Activity.onResume()中注册广播接收器,那就应该在Activity.onPause()中去解除注册。(不要在“paused”之后再去接收intent意图,这将减少不必要的系统开销)。不要在 Activity.onSaveInstanceState()中解除BroadcastResceiver的注册,因为当用户会退到历史栈(作者注:即activity的pop操作,例:a->b,b->a(由b返回a)此处的b->a即为pop操作)时,不会执行该方法。
以下是两个主要的能够被接收的广播类型:
-
** 普通广播 (由 Context.sendBroadcast发出)异步发出。所有广播接收器都没有被定义接收广播的顺序,一般在同一时间接收广播。这样做更加高效,但是这也意味着广播接收者无法接收广播(作者注:被其它接收器)的处理结果或者阻断广播的传递。
-
** 有序广播 (由 [Context.sendOrderedBroadcast](https://developer.android.com/reference/android/content/Context.html#sendOrderedBroadcast(android.content.Intent, java.lang.String))发出)每次只发送给一个广播接收器。当每个广播接收器依次执行时,它可以向下一个广播接收器传播(作者注:由该前一个广播接收器修改的)结果,或者它甚至可以阻断该广播,另该广播不能被下一个广播接收器接收到。有序广播的传播顺序由意图过滤器的 android:priority属性控制(作者注:例<intent-filter android:priority="100">);定义了同一优先级的广播接收器接收顺序随机。
即使是普通广播,系统在某些情况下也只会没辞职将它发送给一个广播接收器,尤其是对于那些可能创建新进程的接收者,为了防止创建新进程造成的系统过载,每次只有一个接收器可以运行。但是,在这种情况下,由于无序语法的定义:这些广播接收器依然不能返回它们的结果或者阻断广播的传播。
请注意,尽管这里的Intent意图类用于发送或者接收广播,但是它与在Context.startActivity()中使用的郁郁开启Activity的Intent的原理是完全不同的。广播接收器是没有办法查看或者捕捉用于startActivity()的Intent的。同理,当你广播一个意图,你也不会找到或者打开Activity。这两种操作的语义是不同的:开启Activity的Intent是修改用户实时交互界面的前台操作;发送广播的Intent是用户通常不会注意到的后台操作。
广播接收者类(由manifest中的 <receiver>标签注册的)是应用生命全周期的重要部分。
这里的主题:
开发人员导读
要了解有关如何接收或解析intents,请阅读 Intents and Intent Filters 开发人员导读。
安全
与 Context接口结合和使用的广播接收器从本质上来说是一个跨应用的设备,所以你必须得防止其他应用滥用你的接收器功能。以下是要考虑的几点:
- Intent类的命名空间是全局的。请保证给Intent添加的action的名字以及其他字符串是被定义在你的私人命名空间的,否则你将可能不小心与其他应用产生冲突。
- 当你使用 [registerReceiver(BroadcastReceiver, IntentFilter)](https://developer.android.com/reference/android/content/Context.html#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter))注册广播接收器时,其他应用也可以给它发送广播。你可以通过以下描述的权限来控制谁可以给它发送广播。
- 当你在应用的清单文件中注册广播接收器,并且为它添加了 intent-filters* (作者注:意图过滤器) *,任何其他应用还是都可以忽视过滤器给它发送广播。为了阻止其它应用发送,可以使用android:exported="false"属性使它变的不可达。
- 当你使用sendBroadcast(Intent)或相关方法时,通常其他应用也可以接收这些广播。你可以通过以下描述的权限控制它。或者,在 ICE_CREAM_SANDWICH*(作者注:Android 4.0.) *下,你可以通过Intent.setPackage安全的限制广播仅发送给一个应用。
在使用LocalBroadcastManager时,所有这些问题都不会出现,被发送的intents不会被发送到当前应用外。
访问权限可以在广播发送者或者接收者中设置。
在发送时设置访问权限,你需要提供一个非空的权限给[sendBroadcast(Intent, String)](https://developer.android.com/reference/android/content/Context.html#sendBroadcast(android.content.Intent, java.lang.String))
或 [sendOrderedBroadcast(Intent, String, BroadcastReceiver, android.os.Handler, int, String, Bundle)](https://developer.android.com/reference/android/content/Context.html#sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle))* (作者注:关于自定义权限参考) *。只有当广播接收器具有这个权限(通过 <uses-permission>
标签在AndroidManifest.xml中申明)才可以接收相应广播。
在接收设置权限,你需要在注册接收器是提供一个非空的权限,无论是通过 [registerReceiver(BroadcastReceiver, IntentFilter, String, android.os.Handler)](https://developer.android.com/reference/android/content/Context.html#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler))注册还是通过<receiver>
标签在AndroidManifest.xml静态注册。只有当广播具有这些权限(通过 <uses-permission>标签在AndroidManifest.xml中声明)才可以发送给接收者。
更多有关权限和安全的信息请参考 Security and Permissions 文档。
广播接收者生命周期
广播接收器对象仅当调用 [onReceive(Context, Intent)](https://developer.android.com/reference/android/content/BroadcastReceiver.html#onReceive(android.content.Context, android.content.Intent))时有效。一旦这个方法return了,系统就认为这个对象应该被结束掉并且不再有效。
这对于在[onReceive(Context, Intent)](https://developer.android.com/reference/android/content/BroadcastReceiver.html#onReceive(android.content.Context, android.content.Intent))中的具体实现就是十分重要的一点:涉及到要求异步操作的代码不应该在此处编写,因为为了处理异步操作,你需要获取异步操作的结果,但是在那时广播接收器可能已经不再有效,并且系统可以在异步操作结束前杀死该进程。
特别是你不应该在广播接收器中显示对话框或绑定服务。对于前者,你应该 NotificationManagerAPI来代替使用。对于后者,你应该使用Context.startService()来发送命令给服务。
进程生命周期
一个正在运行广播接收器的进程(意思是,正在执行[onReceive(Context, Intent)](https://developer.android.com/reference/android/content/BroadcastReceiver.html#onReceive(android.content.Context, android.content.Intent))方法)被认为是前台进程,除非是在极端内存压力的情况下,否则该进程将被系统保持运行状态。
一旦从onReceive()返回了,那么广播接收器不再有效,它的宿主进程的级别将降为与其它应用程序组件相同。这十分重要,因为一旦该进程仅仅运行了一个广播接收器(这是一种情况:一个用户从来没有交互过的应用),然后在onReceive()方法返回时,系统将该进程视为空进程并且为了给其他更重要的进程提供更多资源将该进程杀死。
这意味着对于耗时操作,你应该使用 Service结合广播接收器使用,来保证宿主进程在你的操作全程保持有效。
*(作者注:第一次翻译,有错误的话希望多多提点,多包容咯) *
<br /><br />
二、总结
(一)静态注册和动态注册的特点
- 静态注册:无论宿主应用程序是否处于活动状态,都会进行广播监听,比如某个程序时监听内存的使用情况的,当在手机上安装好后,不管该应用程序是处于什么状态,都会执行改监听方法中的内容。
- 动态注册:在代码中进行注册后,当应用程序关闭后,就不再进行监听。
参考链接
(二)动态注册与解除注册的时机
动态注册的[Context.registerReceiver()](https://developer.android.com/reference/android/content/Context.html#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter))最好是在onCreate()中执行,解除注册的unregisterReceiver(BroadcastReceiver receiver)在onDestroy()中执行。
原因:android 中的注销、内存回收、View视图的回收,最好都在onDestroy中进行,在onStop、onPause中有的情况下会有异常。
(三)关于广播的自定义权限的使用
(四)广播的生命周期
** 广播接收者被认为仅当它执行这个方法时是活跃的。当onReceive()返回后,它是不活跃的。**
有一个活跃的广播接收者的进程是受保护的,不会被杀死。但是当别的进程需要被占用的内存时,系统可以在任何时候杀死仅有不活跃组件的进程。
这带来一个问题,当一个广播消息的响应费时的,应该在独立的线程中做这些事,远离用户界面其它组件运行的主线程。如果onReceive()衍生线程然后返回,整个进程,包括新的线程,被判定为不活跃的(除非进程中的其它应用程序组件是活跃的),将使它处于被杀的危机。解决这个问题的方法是onReceive()
启动一个服务,让服务做这个工作,因此系统知道进程中有活跃的工作在做。(进程升级为服务进程,Android进程回收优先级参考)
(五)广播的应用
- 自定义广播接收器子类,实现onReceive()方法
- 注册广播:静态注册或动态注册
- 若为动态注册,则需要解除注册
实例参考跳转
<br />
***感谢各位前辈的分享精神 ***
参考链接汇总:
BroadcastReceiver官方文档
BroadcastReceiver自定义权限定义及使用
Android进程回收优先级
BroadcastReceiver应用实例
网友评论