Android四大组件之一BroadcastReceiver总结

本文详细介绍了Android四大组件之一的BroadcastReceiver,包括定义、作用、应用场景、实现原理、注册方式和不同类型广播。特别讨论了在Android8.0后如何接收开机广播以及不同注册方式下OnReceive方法中Context的区别。
摘要由CSDN通过智能技术生成

1、定义

BroadcastReceiver即广播,属于Android四大组件之一

广播分:广播发送者、广播接收者

 

2、作用

监听其它应用/系统应用发出的消息,自身做出响应。

 

3、应用场景

1、不同应用之间通信;

2、应用内通信;

3、获取系统一些状态变化;

 

4、实现原理

广播使用观察者模式,基于消息发布/订阅事件模型

 

5、广播注册方式

注册方式分:静态注册、动态注册

静态注册:在AndroidManifest.xml里通过****标签声明

此 App首次启动时,系统会自动实例化mBroadcastReceiver类,并注册到系统中。

<receiver 
    android:enabled=["true" | "false"]
//此broadcastReceiver能否接收其他App的发出的广播
//默认值是由receiver中有无intent-filter决定的:如果有intent-filter,默认值为true,否则为false
    android:exported=["true" | "false"]
    android:icon="drawable resource"
    android:label="string resource"
//继承BroadcastReceiver子类的类名
    android:name=".mBroadcastReceiver"
//具有相应权限的广播发送者发送的广播才能被此BroadcastReceiver所接收;
    android:permission="string"
//BroadcastReceiver运行所处的进程
//默认为app的进程,可以指定独立的进程
//注:Android四大基本组件都可以通过此属性指定自己的独立进程
    android:process="string" >

//用于指定此广播接收器将接收的广播类型
//本示例中给出的是用于接收网络状态改变时发出的广播
 <intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</receiver>

 

动态注册:

在代码中调用Context.registerReceiver()方法

对于动态广播,有注册就必然得有注销,否则会导致内存泄露

  1. 不在onCreate() & onDestory() 或 onStart() & onStop()注册、注销是因为:
    当系统因为内存不足(优先级更高的应用需要内存)要回收Activity占用的资源时,Activity在执行完onPause()方法后就会被销毁,有些生命周期方法onStop(),onDestory()就不会执行。当再回到此Activity时,是从onCreate方法开始执行。
  2. 假设我们将广播的注销放在onStop(),onDestory()方法里的话,有可能在Activity被销毁后还未执行onStop(),onDestory()方法,即广播仍还未注销,从而导致内存泄露。
  3. 但是,onPause()一定会被执行,从而保证了广播在App死亡前一定会被注销,从而防止内存泄露。

 

6、广播类型

普通广播、系统广播、有序广播、App内广播(LocalBroadcastManager类)

按发送方式有:

显示广播:

Intent指定了组件名称(setPackage()或setComponent()),这个Intent为显式Intent,用它发送的广播为显式广播。广播接收者直接就是指定的组件名称对应的广播接收者。

Intent intent = new Intent();
//同时显式指定组件名
intent.setComponent(new ComponentName(MainActivity.this,MyReceiver.class));
context.sendBroadcast(intent)

隐式广播:

Intent指定action, 这个Intent则为隐式Intent,使用它发送的广播则为隐式广播。系统通过IntentFilter去查找的隐式广播接收者。

示例

//隐式intent,发送隐式广播
Intent intent = new Intent("com.demo.recriver");
context.sendBroadcast(intent);

Android8.0限制隐式广播的关键代码逻辑如下 (BroadcastQueue.java)

             } else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
                        || (r.intent.getComponent() == null
                            && r.intent.getPackage() == null
                            && ((r.intent.getFlags()
                                    & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0)
                            && !isSignaturePerm(r.requiredPermissions))) {
                    mService.addBackgroundCheckViolationLocked(r.intent.getAction(),
                            component.getPackageName());
                    Slog.w(TAG, "Background execution not allowed: receiving "
                            + r.intent + " to "
                            + component.flattenToShortString());
                    skip = true;
                }
            }
        }

Android8.0后如何接收开机广播?

1)并配置了白名单

源码目录/frameworks/base/data/etc/framework-sysconfig.xml

        if (action != null) {
            if (getBackgroundLaunchBroadcasts().contains(action)) {
                if (DEBUG_BACKGROUND_CHECK) {
                    Slog.i(TAG, "Broadcast action " + action + " forcing include-background");
                }
                intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
            }

2)系统为白名单添加FLAG_RECEIVER_INCLUDE_BACKGROUND的标志位;

3)接收方静态注册开机广播接收器;

 

7、特别注意

对于不同注册方式的广播接收器回调OnReceive(Context context,Intent intent)中的context返回值是不一样的:

  • 对于静态注册(全局+应用内广播),回调onReceive(context, intent)中的context返回值是:ReceiverRestrictedContext;
  • 对于全局广播的动态注册,回调onReceive(context, intent)中的context返回值是:Activity Context;
  • 对于应用内广播的动态注册(LocalBroadcastManager方式),回调onReceive(context, intent)中的context返回值是:Application Context。
  • 对于应用内广播的动态注册(非LocalBroadcastManager方式),回调onReceive(context, intent)中的context返回值是:Activity Context;
  • 进程生命周期错误的一个常见示例是当 BroadcastReceiver 在其 BroadcastReceiver.onReceive() 方法中接收到一个 Intent 时,它会启动一个线程,然后从该函数返回。一旦返回,则系统会认为 BroadcastReceiver 不再处于活动状态,因此不再需要其托管进程(除非其中有其他应用组件处于活动状态)。因此,系统可能会随时终止进程以回收内存,这样会终止在进程中运行的衍生线程。要解决这个问题,通常可以从 BroadcastReceiver 调度 JobService,这样系统就知道进程中还有处于活动状态的任务正在进行中。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值