Android 四大组件之Broadcast【一】

一,什么是广播?

广播, 做为Android的四大组件之一,被用于发送和接收,来自系统或其它app的消息。其设计原理,是基于观察者模式来设计的,即先订阅,后接收。广播消息,并不受限于某一个单一进程。因此,它可以用于跨进程间的通信,在多个App之间传递消息。

二,广播的分类。

一,根据广播的订阅(定义)方式和生命周期,我们可以将广播归纳为2种类型,即静态广播与动态广播。

  • 静态广播
    静态注册的广播,在App被安装后,就自动被系统的PackageManager注册保存起来。这样,哪怕你的app,没有在运行,你的app也可以接收到广播。订阅这样一个广播,我们需要分2步实现。第1步,是创建一个类,继承自BroadcastReceiver。第2步,是在配置清单文件(AndroidManifest.xml)里面,进行配置第1步所创建的类。
  1. 创建继承自BroadcastReceiver的类,代码如下:
class MyBroadcastReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
           // 当接收到广播时,这个方法会被调用,intent参数,包含了广播所附带的数据。
    }
}
  1. 在AndroidManifest.xml里面,配置刚刚定义的类。这个标签,必须放在标签中间,与标签同层级。
<receiver android:name=".MyBroadcastReceiver"  android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
        <action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
    </intent-filter>
</receiver>

  • 动态广播
    动态广播,是指通过代码,来动态订阅。每一个动态广播,都绑定一个上下文Context,要么是某个Activity的,要么是Application的。它的特点是,生命周期只局限于某个页面的生命周期,亦或是App的生命周期。当绑定广播的Activity或App被销毁后,就无法再接收广播。同样地,订阅这样一个广播,我们需要分3步走:
  1. 创建继承自BroadcastReceiver的类,代码如下:
class MyBroadcastReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
           // 当接收到广播时,这个方法会被调用,intent参数,包含了广播所附带的数据。
    }
}
  1. 创建BroadcastReceiver子类的实例,代码如下:
val br: BroadcastReceiver = MyBroadcastReceiver()
  1. 创建IntentFilter,添加订阅事件,并注册广播。
val filter = IntentFilter()
// 添加要订阅的广播事件
filter.addAction(Intent.ACTION_SCREEN_OFF)
// 注册广播
registerReceiver(br, filter)

三,取消注册广播。

因为动态广播受限于Activity或Application的生命周期,简而言之,动态广播应该在合适的时机被取消注册。让我们先看看,如何取消注册一个广播:

// val br: BroadcastReceiver = MyBroadcastReceiver()
unregisterReceiver(br)

可以看到,取消注册广播很简单,一行代码就搞定。那么,为什么,需要在合适的时机去取消注册广播?因为,动态广播(非本地广播)会持有Activity的上下文context。在Activity被销毁时,如果没有取消所有注册的广播,就会造成内存泄露。让我们看看源码部分,关于注册和反注册广播接收者的部分代码。在LoadedApk类里面,有一个成员变量,如下所示:

 private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> 
 mReceivers = new ArrayMap<>();

可以看到,每一个Context,可以绑定多个广播接收者(BroadcastReciver)。让我们再看看,取消注册广播的源码实现部分。可以看到,只有当map.size为0时,即所有广播接收者都取消注册后,这个Context才会被释放。

   // 省略....
   synchronized (mReceivers) {
            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context);
            LoadedApk.ReceiverDispatcher rd = null;
            if (map != null) {
                rd = map.get(r);
                if (rd != null) {
                    map.remove(r);
                    if (map.size() == 0) {
                        mReceivers.remove(context);
                    }
                    // 省略其它代码
               }
           }
      }
     // 省略....

四,发送广播消息【未完待续】。

根据广播消息的接收次序,我们可以把广播消息,分为有序广播和无序广播。

  • 有序广播
    有序广播是指,当一个广播消息被发送出去时,多广播接收者,会依次接收到这个消息,同一时间内,只有一个广播接收者在处理这条广播消息,任意一个正在处理广播消息的广播接收者,都可以中断这个传播链。其原理,类似于责任链模式。我们,可以通过,配置这个属性android:priority,来提高广播接收者的优先级,优先级越高的,越先接收到消息。这个属于的值,必须是整数,而且,数值越大,优先级越高。

五,广播对保活的影响。

当广播接收者,接收到广播消息时,onReceive() 方法会被调用。在onReceive()方法执行期间,当前应用会被认为是前台应用。但当这个方法执行完毕后,当前应用的优先级,又会降回原来app所处的保活等级。因此,可以通过在onReceive()里面,创建一个守护线程,来确保onReceive()一直在执行,就可以使得app所处的保活等级较高,不会轻易被系统回收。【注:这也无法根本性的解决保活问题,只能说是最大化保活的手段之一。可以在面试,被问到如何保活时,提出来讲讲】


参考资料:

  1. Broadcasts Overview 广播知识概览
  2. LoadedApk.java
  3. ContextImpl.java
  4. android:priority 属性文档
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值