Android四大组件之BroadcastReceiver与本地广播——LocalBroadcastManager

BroadcastReceiver

Broadcast 是一种广泛运用在一个设备中不同应用程序之间传输信息的机制。而BroadcastReceiver 是对发送出来的Broadcast进行过滤接受并响应的一类组件。可以使用BroadcastReceiver 来让应用对一个外部的事件做出响应。
但是BroadcastReceiver生命周期很短 不能做耗时操作 要提交给service


设置广播接收方式

可分为普通广播 和 有序广播
普通广播:

sendBroadcast(intent)

所有接受者都可以同时接收到,接收者相互之间不会有影响,不能终止别的接受者接收

有序广播

sendOrderBroadcast(Intent intent,String permission)

有序广播 可以截断 可以处理数据(比如广播给第一个,然后第一个收到后可以传递一些数据给第二个)

在注册广播中的< intent-filter>中使用android:priority属性。这个属性的范围在-1000到1000,数值越大,优先级越高

第二个参数为 权限 设置为null 则 表示不要求接收者声明指定的权限,如果不为null则表示接收者若要接收此广播,需声明指定权限
例如系统的短信就是有序广播的形式,一个应用可能是具有拦截垃圾短信的功能,当短信到来时它可以先接受到短信广播,必要时终止广播传递 这时软件就要通过权限设置拦截短信

在广播接收器中使用setResultExtras方法将一个Bundle对象设置为结果集对象,传递到下一个接收者那里,这样优先级低的接收者可以用getResuttExtras获取到最新的经过处理的信息集合


静态注册(无论应用程序是否运行 receiver都会监听相应注册过的action)

一、File->new ->others->brocardReveiver
通过该方式自动生成 继承brocardReveiver的类
并且会在 manifest.xml中自动注册
否则要自己去manifest.xml中注册

 <receiver
            android:name=".Utils.TestReceiver"
            android:enabled="true"
            android:exported="true"></receiver>

android:enabled
android:enabled属性来限制Android系统的行为。这个属性表明Android系统是否可以被实例化应用程序组件,如果其值为true,则说明应用程序组件可以被Android系统自动实例化;如果为false,则说明实例化组件的工作需要手工完成

android:exported
是否支持其它应用发送广播到该app 若配置了<intentfilter 则默认为true 否则默认为false


二、设置接收的广播action

<receiver
            android:name=".Utils.TestReceiver"
            android:enabled="true"
            android:exported="true">
		 <intent-filter
		  <!--设置静态广播优先级-->
		  <!--android:priority="1000"-->
		 >
                <action android:name="NetStatusAction" />
            </intent-filter>
            </receiver>

三、重写onReceive方法
当接收到广播信息时,则会执行该方法
onReceive方法不能执行耗时操作(15s) 要去开启子线程或者通过serivce进行耗时操作

public class TestReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
         if(("NetStatusAction").equals (action)){
            Toast.makeText(context,"NetStatusAction执行",Toast.LENGTH_SHORT).show();
        }
    }
}

四、发送广播

Intent intent = new Intent();
        intent.setAction("NetStatusAction");
        sendBroadcast(intent);

动态广播 (与Activity或applicationContext生命周期有关)##

一、创建类继承BroadcastReceiver,重写onReceive方法,类似上面
如 DynamicReceiver

二、

// 声明动态广播
DynamicReceiver dynamicReceiver;  

// 相应事件中
IntentFilter filter = new IntentFilter();  
        filter.addAction("xxxAction");  
        //设置动态优先级 
        //filter.setPriority(1000);
        dynamicReceiver = new DynamicReceiver();  
        (applicationContext.)registerReceiver(dynamicReceiver,filter);  

三、相应的onDestroy或者onStop中,解除注册
如果是applicationContext注册的得通过applicationContext解注册 通过activity解注册并不是真正的解注册

  (applicationContext.)unregisterReceiver(dynamicReceiver);

如果多个界面中要解注册 则可以用一个单例的广播,或者每个界面去register/unregister


两种方式的主要区别:

1 静态方式 系统会唤醒应用 去接收广播

2 静态方式 系统会创建一个新的BroadcastReceiver组件对象去接收每一个广播(接收一个创建一个 因此不能在构造函数或者在类中创建对象和内存)
会在onReceive的持续时间内有效 一旦该函数返回 则对象销毁

而动态方式则可以自己设置广播注册和注销的时间

3 动态方式比静态方式开启速度快

4 静态方式注册的广播,如果要在内部类中,必须要声明为public static,否则会报错

版本改动:
在Android7.0以上 无法使用清单声明隐式(implicit)广播的接收者(不针对本地应用的广播),除了几个免除该限制的隐式广播。
在Android8.0以上 无法在清单文件中为绝大多数隐式广播(不针对你应用的本地广播)声明接收者
在大多数情况下,您可以使用Jobscheduler针对特殊系统消息进行相应接收和处理。
在Android9.0以上 NETWORK_STATE_CHANGED_ACTION broadcast不能获取用户的地址位置信息了
系统的WIFI广播 不再包含SSIDs, BSSIDs, connection information, or scan results信息了
得通过 getConnectionInfo() 获取


LocalBroadcastManager

优点:
广播是重量级的、消耗资源较多的方式,因此若只是在自己的app内进行广播,可以采用LocalBroadcastManager 更安全高效

1 发送的广播是在APP内的,不会泄漏到别的APP中,并且别的APP的广播也不会接收,更安全
2 比BroadcastReceiver更高效

缺点
只能实现app内的广播,不同app间,以及系统的广播还是得用BroadcastReceiver 不能跨进程通信

与BroadcastReceiver的根本区别 :
BroadcastReceiver底层是Binder机制,因此可以实现跨进程通信,而LocalBroadcastManager 是Handler
基于主线程的 Looper 新建了一个 Handler,handleMessage中会调用接收器对广播的消息进行处理


基本使用:

一、创建自定义接收器

public class LocalBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        //TODO
    }
}

二、注册广播接收器

LocalBroadcastReceiver localReceiver = new LocalBroadcastReceiver();
LocalBroadcastManager.getInstance(applicationContext)
.registerReceiver(localReceiver, new IntentFilter(ACTION_LOCAL_SEND));

这里的IntentFilter可以自定义不同的Action 类似BroadcastReceiver的IntentFilter

三、发送广播

LocalBroadcastManager.getInstance(applicationContext)
sendBroadcast(new Intent(ACTION_LOCAL_SEND));

四、注销广播接收器

LocalBroadcastManager.getInstance(applicationContext).unregisterReceiver(localReceiver);

注意的点:
1 LocalBroadcastManager没有优先级的设置
2 LocalBroadcastManager最好传系统的applicationContext 否则容易造成内存泄漏


系统广播

问题1 若发送了非protected的广播 会打印这个日志:

E/ActivityManager: Sending non-protected broadcast 

该异常已被ActivityManager捕获,并不会导致crash

原因:
app是系统app 发送了一个不带protected-broadcast属性的广播
系统app:
设置了uid为 android.uid.system,android.uid.phone,android.uid.log,android.uid.nfc,android.uid.bluetooth,android.uid.shell的并且被签过名的app是系统app
或者在指定目录中的app为系统app “指定目录”包括/vendor/overlay,/system/framework,/system/priv-app,/system/app,/vendor/app,/oem/app

解决:
1 给该广播加上protected-broadcast属性

<protected-broadcast android:name="android.intent.action.XXX_ACTION" />

这样 这种action只能由系统app发起,而不能由非系统app发起 否则会引起crash

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值