【Android基础组件】BroadCast——广播三两事

【Android基础组件】BroadCast——广播三两事

本文介绍了Android四大组件之一的广播的相关基础理论知识,想了解更多可参阅安卓官方文档或技术书籍。

什么是广播?

一般来说,广播可作为跨应用和普通用户流之外的消息传递系统。Android 应用与 Android 系统和其他 Android 应用之间可以相互收发广播消息,这与发布-订阅设计模式相似。这些广播会在所关注的事件发生时发送。应用也可以注册接收特定的广播。广播发出后,系统会自动将广播传送给同意接收这种广播的应用。

举栗时间
  • Android 系统会在发生各种系统事件时发送广播——如系统启动或设备开始充电时。
  • 应用可以发送自定义广播来通知其他应用它们可能感兴趣的事件——如一些新数据已下载。

有哪些广播?

本地广播与全局广播
  • 本地广播,只能够在应用程序的内部进行传递 ,并且相应广播接收器也只能接收来自应用程序发出的广播。
  • 全局广播便是能在应用之间进行传递的广播。相比之下,本地广播的的效率更高(无需进行进程间通信),而且您无需担心其他应用在收发您的广播时带来的任何安全问题。
标准广播与有序广播
  • 标准广播是一种完全异步执行的广播,广播发出后所有的BroadcastReceiver几乎会在同一时刻收到这条广播消息。这意味着该广播的效率比较高,但无法被截断。
  • 有序广播则是一种同步执行的广播,广播发出后,同一时间只有一个接收器会收到广播消息,在执行完onReceive方法后,广播才会继续传递。这意味着此时的接收器是有先后顺序的,并且在前面收到广播的接收器还可以对正在传递的广播进行截断(调用abortBroadcast方法)。接收器的运行顺序可以通过匹配的 intent-filter 的 android:priority 属性来控制;具有相同优先级的接收器将按随机顺序运行。
隐式广播与显式广播
  • 隐式广播:未指定发送给哪个应用程序的广播。注意,在Android 8.0之后的系统中,静态注册的BroadcastReceiver是无法接受除少数特殊的系统广播之外的隐式广播的。
  • 显式广播:经由setPackage()方法指定了目标程序的广播。
系统广播

系统广播指的是系统在发生各种系统事件时(如系统进入和退出飞行模式时)自动发送的广播。

广播怎么用?

广播的使用主要包括以下几个步骤:

  1. 编写广播,实现onReceive方法中的逻辑
  2. 在APP中对所需接收的广播进行注册
  3. 在某处发送广播
    sendOrderedBroadcast(Intent, String);//发送有序广播。
    sendBroadcast(Intent); //发送标准广播。
    LocalBroadcastManager.sendBroadcast(); //发送本地广播
    
  4. 在不再需要该广播时取消注册
怎么注册广播?
  • 静态注册:清单声明的接收器(系统将在广播发出后启动应用)
    系统软件包管理器会在应用安装时注册接收器。然后,该接收器会成为应用的一个独立入口点,这意味着如果应用当前未运行,系统可以启动应用并发送广播。
  • 动态注册:代码中调用registerReceiver(BroadcastReceiver, IntentFilter)注册的接收器
    如注册的是本地广播,请调用 LocalBroadcastManager.registerReceiver(BroadcastReceiver, IntentFilter)。
    注意:需要停止接收广播时,需调用unregisterReceiver(BroadcastRecveiver),特别是在不再需要接收器或上下文不再有效时,务必取消注册。请注意注册和注销接收器的位置,比方说,如果您使用 Activity 上下文在 onCreate(Bundle) 中注册接收器,则应在 onDestroy() 中注销,以防接收器从 Activity 上下文中泄露出去。如果您在 onResume() 中注册接收器,则应在 onPause() 中注销,以防多次注册接收器(如果您不想在暂停时接收广播,这样可以减少不必要的系统开销)。请勿在 onSaveInstanceState(Bundle) 中注销,因为如果用户在历史记录堆栈中后退,则不会调用此方法。
接收器的工作时间

接收器的工作时间与注册的上下文有关,只要上下文有效,接收器便能持续工作。

举栗时间
  • 如Activity中创建的接收器,只要Activity未被销毁,接收器便能收到广播。
  • 在应用上下文中注册的接收器,只要应用在运行,便可以收到广播。
使用时需要注意什么?
不可在onReceive方法中启动长时间运行的后台线程

当 BroadcastReceiver 在其 BroadcastReceiver.onReceive() 方法中接收到一个 Intent 时,它会启动一个线程,然后从该函数返回。一旦返回,则系统会认为 BroadcastReceiver 不再处于活动状态,因此不再需要其托管进程(除非其中有其他应用组件处于活动状态)。因此,系统可能会随时终止进程以回收内存,这样会终止在进程中运行的衍生线程
如要执行长时间运行的工作:

  • 在接收器的 onReceive() 方法中调用 goAsync(),并将 BroadcastReceiver.PendingResult传递给后台线程。这样,在从 onReceive()返回后,广播仍可保持活跃状态。不过,即使采用这种方法,系统仍希望您非常快速地完成广播(在 10秒以内)。为避免影响主线程,它允许您将工作移到另一个线程。
  • 使用 JobScheduler 调度作业,这样系统就知道进程中还有处于活动状态的任务正在进行中。
如果您不需要向应用以外的组件发送广播,就使用LocalBroadcastManager 来收发本地广播。

LocalBroadcastManager 效率更高(无需进行进程间通信),并且您无需考虑其他应用在收发您的广播时带来的任何安全问题。本地广播可在您的应用中作为通用的发布/订阅事件总线,而不会产生任何系统级广播开销。

优先使用动态注册而不是静态注册

如果有许多应用在其清单中注册接收相同的广播,可能会导致系统启动大量应用,从而对设备性能和用户体验造成严重影响。有时,Android 系统本身会强制使用动态注册的接收器。例如,CONNECTIVITY_ACTION 广播只会传送给动态注册的接收器。

请勿使用隐式 intent 广播敏感信息

任何注册接收广播的应用都可以读取这些信息。您可以通过以下三种方式控制哪些应用可以接收您的广播:

  • 可以在发送广播时指定权限。
  • 在 Android 4.0 及更高版本中,可以在发送广播时使用 setPackage(String)指定软件包。系统会将广播限定到与该软件包匹配的一组应用。
  • 可以使用 LocalBroadcastManager 发送本地广播。
当您注册接收器时,任何应用都可以向您应用的接收器发送潜在的恶意广播

您可以通过以下三种方式限制您的应用可以接收的广播:

  • 可以在注册广播接收器时指定权限。
  • 对于静态注册的接收器,您可以在清单中将 android:exported 属性设置为“false”。这样一来,接收器就不会接收来自应用外部的广播。
  • 可以使用 LocalBroadcastManager 限制您的应用只接收本地广播。
广播操作的命名空间是全局性的

请确保在您自己的命名空间中编写操作名称和其他字符串,否则可能会无意中与其他应用发生冲突。

请勿从广播接收器启动 Activity,否则会影响用户体验,尤其是有多个接收器时

相反,可以考虑显示通知。

拓展——发布/订阅模式与观察者模式区别

笔者在初次接触广播时误以为广播使用的是观察者模式,实则不然,而二者最大的区别在于调度的地方不同,观察者模式是由具体目标调度的,而发布/订阅模式是统一由调度中心调度的。
文末放上发布/订阅模式与观察者模式的对比博客,有疑惑的可了解:【设计模式(三):观察者模式与发布/订阅模式区别】https://www.cnblogs.com/lovesong/p/5272752.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值