Android基础知识巩固:关于PendingIntent和广播
平时使用广播的场合比较多,但细节的东西,看过了也没有总结,以至于某些场合有小问题,还是要把原理和属性搞清楚才能运用自如。
其实也是自己比较懒,先看别人的blog,有个概念再去官网看英文的能好理解一些。
这篇补充上一篇消息推送的知识,先罗列一些基础知识,再说自己不足的地方和问题。
照例,先搬砖:
2. Android Service 服务(二)—— BroadcastReceiver
3. Android----基础----第八天----BroadcaseReceiver和通知
4. Android开发之BroadcastReceiver详解
第1篇里的重点是:
- Intent和PendingIntent的区别
a. Intent是立即使用的,而PendingIntent可以等到事件发生后触发,PendingIntent可以cancel
b. Intent在程序结束后即终止,而PendingIntent在程序结束后依然有效
c. PendingIntent自带Context,而Intent需要在某个Context内运行
d. Intent在原task中运行,PendingIntent在新的task中运行
第2,4篇里的重点是:
BroadcastReceiver,顾名思义就是“广播接收者”的意思,它是Android四大基本组件之一,这种组件本质上是一种全局的监听器,用于监听系统全局的广播消息。它可以接收来自系统和应用的的广播。
由于BroadcastReceiver是一种全局的监听器,因此它可以非常方便地实现系统不同组件之间的通信。比如Activity与通过startService()方法启动的Service之间通信,就可以借助于BroadcastReceiver来实现。
当应用发出一个Broadcast Intent之后所匹配该Intent的组件都可能被启动。
- 两种注册方式
a. 静态注册方式,由系统来管理receiver,而且程序里的所有receiver,可以在xml里面一目了然。通过这种方式注册的广播为常驻型广播,也就是说如果应用程序关闭了,有相应事件触发,程序还是会被系统自动调用运行。
b. 动态注册方式,隐藏在代码中,比较难发现;需要特别注意的是,在退出程序前要记得调用Context.unregisterReceiver()方法。一般在activity的onStart()里面进行注册, onStop()里面进行注销。官方提醒,如果在Activity.onResume()里面注册了,就必须在Activity.onPause()注销。通过这种方式注册的广播为非常驻型广播,即它会跟随Activity的生命周期,所以在Activity结束前我们需要调用unregisterReceiver(receiver)方法移除它。
- 生命周期
一个BroadcastReceiver 对象只有在被调用onReceive(Context, Intent)的才有效,当从该函数返回后,该对象就无效的了,结束生命周期。因此从这个特征可以看出,在所调用的onReceive(Context, Intent)函数里,不能有过于耗时的操作,不能使用线程来执行。对于耗时的操作,应该在startService中来完成。因为当得到其他异步操作所返回的结果时,BroadcastReceiver 可能已经无效了。
In particular, you may not show a dialog or bind to a service from within a BroadcastReceiver. For the former, you should instead use the NotificationManager
API. For the latter, you can use Context.startService()
to send a command to the service.
特别的,BroadcastReceiver中也不能展示dialog或者去绑定service。前者可以用NotificationManager代替,后者可以用Context.startService()发送命令给service。
- 有序广播和无序广播
第3篇里介绍了广播和通知的基本知识点,这种脑干图的学习方式也不错。
看完上面的知识,还有疑问?
官网:http://developer.android.com/reference/android/content/BroadcastReceiver.html
首先:如果广播没有必要在应用之间传递,建议用LocalBroadcastManager,能避免很多一般广播存以下的安全性问题。
Receivers used with the Context
APIs are by their nature a cross-application facility, so you must consider how other applications may be able to abuse your use of them. Some things to consider are:
-
The Intent namespace is global. Make sure that Intent action names and other strings are written in a namespace you own, or else you may inadvertently conflict with other applications.
- Intent的命名空间是全局的,保证自己的Intent的action命名和其他string都是自己指定的名称,防止与其他应用造成名称冲突。
-
When you use
registerReceiver(BroadcastReceiver, IntentFilter)
, any application may send broadcasts to that registered receiver. You can control who can send broadcasts to it through permissions described below. - 当用动态注册时,任何app都能向这个监听器发送广播,可以设置权限控制谁能发送这种广播。permission和user permission,具体官网有介绍。
-
When you publish a receiver in your application's manifest and specify intent-filters for it, any other application can send broadcasts to it regardless of the filters you specify. To prevent others from sending to it, make it unavailable to them with
android:exported="false"
. - 作为接收方,如果是配置文件中的静态注册,也设置了intent-filters,那监听器也会收到其他app也能发送的符合过滤规则的广播,可以设置android:exported="false",杜绝接受其他app发出的此类广播。
-
When you use
sendBroadcast(Intent)
or related methods, normally any other application can receive these broadcasts. You can control who can receive such broadcasts through permissions described below. Alternatively, starting withICE_CREAM_SANDWICH
, you can also safely restrict the broadcast to a single application withIntent.setPackage
- 作为发送方,发送广播时,一般其他app都能收到这些广播(有可能没设置上面一条说的,导致收到了其他app不必要的广播),这样可以在发送的时候指定谁可以收到这个广播。比如指定包名等方法。
Process Lifecycle
A process that is currently executing a BroadcastReceiver (that is, currently running the code in its onReceive(Context, Intent)
method) is considered to be a foreground process and will be kept running by the system except under cases of extreme memory pressure.
Once you return from onReceive(), the BroadcastReceiver is no longer active, and its hosting process is only as important as any other application components that are running in it. This is especially important because if that process was only hosting the BroadcastReceiver (a common case for applications that the user has never or not recently interacted with), then upon returning from onReceive() the system will consider its process to be empty and aggressively kill it so that resources are available for other more important processes.
This means that for longer-running operations you will often use a Service
in conjunction with a BroadcastReceiver to keep the containing process active for the entire time of your operation.
正在执行BroadcastReceiver的进程是前台进程,系统会保留这个进程的运行状态,除非极端内存不足。
一旦从onReceive()返回,BroadcastReceiver不在有效,它的宿主进程和其他运行的application有一样的重要级别,如果该宿主只有这一个BroadcastReceiver活动(比如用户一直没有交互操作的app),此时从onReceive()返回后宿主进程将被视为空进程,很容易被回收。
也就是说,对于耗时操作要用service作为与BroadcastReceiver的对接保证操作过程中进程是活动的。