Android广播--BroadcastReceiver 本地广播LocalBroadcastManager 8.0删除静态广播行为

本文主要是介绍Android广播--BroadcastReceiver 本地广播LocalBroadcastManager 8.0删除静态广播行为,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Broadcast Receiver

  • 定义:
    • 使用场景:
  • 广播分类:
  • 隐式广播
    • Android 7.0
    • Android 8.0
  • 广播注册:
    • 静态注册样例:
    • 动态注册样例
  • 广播实现机制:
  • 本地广播:
    • 使用本地广播优势:
    • 本地广播源码解析:
      • LocalBroadcastManager的构造方法
      • LocalBroadcastManager的数据结构
      • 广播注册方法:
      • 广播解除注册方法
      • 发送广播方法
      • 将发送的Intent回调给广播接收器
    • 本地广播总结:
    • 本地广播与全局广播发送方法比较
      • 本地广播
      • 全局广播
  • BroadcastReceiver接收顺序
  • 广播发送方法

定义:

在Android中,Broadcast是一种广泛应用在应用程序之间传输信息的机制,Android中我们要发送的内容是一个Intent,而我们要发送的数据由Intent包装。
而BroadcastReceiver是一个专注于接收广播发出的信息,并作出对应处理的组件。BroadcastReceiver没有用户界面,但是它可以启动Activity来相应接收到的消息,或者使用NotificationManager发出通知来提醒用户

广播类似于Java当中的观察者模式,即被观察者数据发生变化后,给观察者发出通知做相应的数据处理。

使用场景:

  • 同一个APP具有多个进程的不同组件之间的消息通信

    比如获取定位数据或者天气数据的Service放在了一个进程,这时候可以通过广播来与主进程进行数据交换达到更新UI等功能

  • 不同APP之间的组件进行消息通信

    比如系统应用发出来电信息,短信信息,电源信息等。或者一些大公司有多个APP装在用户手机上,这样不同应用之间就可以通过广播来进行通信

广播分类:

  • Normal Boradcast:即普通广播,可以通过Conext.sendBroadcast(intent)、Conext.sendBroadcast(intent,receiverPermission)等发送广播

  • System Broadcast:即系统广播,系统广播在系统内部当特定事件发生时,由系统自动发出,开发者可以接受这些广播;如:开机启动,网络状态改变,拍照,屏幕关闭与开启等特定事件

  • Ordered Broadcast:即有序广播,其实有序广播可以算做是系统广播;有序广播中的“有序”是针对广播接收者而言的,指的是发送出去的广播被BroadcastReceiver按照先后循序接收。有序广播的定义过程与普通广播无异,只是其主要发送方式变为:sendOrderedBroadcast(intent, receiverPermission, …);有序广播特点如下:

    • 多个BroadcastReceiver接收有序广播时,是按照先后顺序接收的,先后顺序判定标准遵循为:将当前系统中所有有效的动态注册和静态注册的BroadcastReceiver按照priority属性值从大到小排序;对于具有相同的priority的动态广播和静态广播,动态广播会排在前面。
    • 先接收的BroadcastReceiver可以对此有序广播进行截断,使后面的BroadcastReceiver不再接收到此广播,也可以对广播进行修改,使后面的BroadcastReceiver接收到广播后解析得到错误的参数值。当然,一般情况下,不建议对有序广播进行此类操作,尤其是针对系统中的有序广播。
  • Local Broadcast:即本地广播,App应用内广播,广播的发送与接收只在当前应用内发生

隐式广播

<receiver android:name=".BootReceiver"android:exported="true"><intent-filter><action android:name="android.intent.action.MANGO"></action><action android:name="android.intent.action.BOOT_COMPLETED"></action><action android:name="android.intent.action.LOCKED_BOOT_COMPLETED"></action></intent-filter>
</receiver>
Intent intent = new Intent();
intent.setAction(BootReceiver.ACTION);
sendBroadcast(intent);
Intent intent = new Intent(this,BootReceiver.class);
intent.setAction(BootReceiver.ACTION);
sendBroadcast(intent);

这种自己定义的【android.intent.action.MANGO】是一个显示广播,而很多跟自己应用无关的action是隐式广播

对于系统发出的广播,基本上都是隐式广播,以前很多应用会在Manifest中为很多系统隐式广播注册接收器,然后通过一些操作来提高自己的应用进程优先级,也就是俗称的【进程保活】,但是如果大家都这样干,将会极大的消耗系统资源,手机也就变的越来越卡

Android 7.0

Google也意识到这个问题了,于是在Android N这个版本做了一些后台优化,删除了三项隐式广播CONNECTIVITY_CHANGE,ACTION_NEW_PICTURE ,ACTION_NEW_VIDEO,以帮助优化内存使用和电量消耗;这样即使你静态注册了这些广播,也不会收到了;但是你如果是动态注册广播,还是可以收到这些广播的

  • 在Android N平台下即使在Manifest.xml清单文件中注册了 CONNECTIVITY_ACTION广播,在网络发生变化时也不会接收到任何的信息。但是正在前台运行的应用程序如果在主线程中通过Context.registerReceiver()动态注册了CONNECTIVITY_ACTION广播,该应用程序仍然可以接收到该广播。(注:这样开发者就可以根据不同的网络状态加载相应的页面信息了,从而提高用户体验)。

  • 应用程序无法发送或接收 ACTION_NEW_PICTURE(拍照) 或 ACTION_NEW_VIDEO(录像) 广播。此项优化会影响所有应用,而不仅仅是面向 Android N 的应用。

Android 8.0

鉴于开发者们肯定更多的只是考虑自己的应用,你可以想象一下手机里的每个应用可能都会去监听网络状态变更、是否拍摄了新照片、安装了新应用、开始充电等等事件。因为这些 App 都在 AndroidManifest.xml 中注册接收这些广播,所以它们总是能被唤醒接收这些广播,即使不在前台,甚至没有运行。Google 也意识到隐式广播被滥用了,因此在 Android O 中清除了非常多的隐式广播。这样即使你静态注册了这些广播,也不会收到了;但是你如果是动态注册广播,还是可以收到这些广播的

但是有一些隐式广播还是可以收到的(我们自己正常发的广播,如果不指定包名, 静态注册的也是收不到的),如下:

ACTION_LOCKED_BOOT_COMPLETED, ACTION_BOOT_COMPLETED
豁免,因为这些广播第一次启动时只发送一次,许多应用程序需要接收这个广播来安排作业,报警等。ACTION_USER_INITIALIZE, "android.intent.action.USER_ADDED", "android.intent.action.USER_REMOVED"
这些广播受到特权许可保护,所以大多数普通应用无法接收。"android.intent.action.TIME_SET", ACTION_TIMEZONE_CHANGED, ACTION_NEXT_ALARM_CLOCK_CHANGED
当时间,时区或闹钟发生变化时,时钟应用可能需要接收这些广播来更新闹钟。ACTION_LOCALE_CHANGED
只有当地区变化时才发送,这不常见。当区域设置更改时,应用程序可能需要更新其数据。ACTION_USB_ACCESSORY_ATTACHED, ACTION_USB_ACCESSORY_DETACHED, ACTION_USB_DEVICE_ATTACHED, ACTION_USB_DEVICE_DETACHED
如果一个应用程序需要知道这些与USB有关的事件,那么目前还没有注册广播的好选择。ACTION_HEADSET_PLUG
由于此广播仅在用户物理连接或断开插头时发送,因此如果应用响应此广播,则不太可能影响用户体验。ACTION_CONNECTION_STATE_CHANGED, ACTION_CONNECTION_STATE_CHANGED, ACTION_ACL_CONNECTED, ACTION_ACL_DISCONNECTED
类似于ACTION_HEADSET_PLUG,如果应用程序接收到这些蓝牙事件的广播,用户体验就不会受到影响。ACTION_CARRIER_CONFIG_CHANGED, TelephonyIntents.ACTION_*_SUBSCRIPTION_CHANGED, "TelephonyIntents.SECRET_CODE_ACTION"
OEM电话应用可能需要接收这些广播。LOGIN_ACCOUNTS_CHANGED_ACTION
某些应用程序需要了解登录帐户的更改,以便他们可以为新帐户和已更改帐户设置计划操作。ACTION_PACKAGE_DATA_CLEARED
仅当用户从“设置”显式清除其数据时才发送,因此广播接收者不太可能显着影响用户体验。ACTION_PACKAGE_FULLY_REMOVED
某些应用程序可能需要在删除另一个软件包时更新其存储的数据; 对于这些应用程序,没有注册此广播的好选择。注意:其他与封装相关的广播(如ACTION_PACKAGE_REPLACED)不能免于新的限制。这些广播是非常普遍的,因为它们对于免除这些播放具有潜在的性能影响。ACTION_NEW_OUTGOING_CALL
为响应用户拨打电话而采取行动的应用程序需要接收此广播。ACTION_DEVICE_OWNER_CHANGED
这种广播不经常发送; 某些应用程序需要接收它,以便他们知道设备的安全状态已更改。ACTION_EVENT_REMINDER
由日历提供商发送事件提醒日历应用程序。由于日历提供程序不知道日历应用程序是什么,因此该广播必须是隐式的。ACTION_MEDIA_MOUNTED, ACTION_MEDIA_CHECKING, ACTION_MEDIA_UNMOUNTED, ACTION_MEDIA_EJECT, ACTION_MEDIA_UNMOUNTABLE, ACTION_MEDIA_REMOVED, ACTION_MEDIA_BAD_REMOVAL
这些广播是由于用户与设备的物理交互(安装或删除存储卷)或作为启动初始化的一部分(可用卷被安装)的结果而发送,因此它们不是常见的情况,并且通常在用户的控制之下。SMS_RECEIVED_ACTION, WAP_PUSH_RECEIVED_ACTION
这些广播由SMS收件人应用程序依赖。

广播注册:

  • 静态注册:在manifest.xml中注册,注册完成就一直运行,也叫常驻型广播,在最新API里,默认情况下如果APP所在进程结束,静态广播也不能接收广播了
  • 动态注册:通过registerReceiver方法在代码里注册,它的生命周期跟随注册它的Activity的生命周期;在Activity的onDestory方法中必须使用unregisterReceiver方法解除注册,否则造成内存泄漏;也叫非常驻型广播

这里写图片描述

静态注册方式,直接在Androidmanifest.xml中注册:

<receiverandroid:exported=["true" |"false"]android:name="string"android:permission="string"android:process="string" ><intent-filter><action android:name="android.net.conn.CONNECTIVITY_CHANGE"/></intent-filter></receiver>

注册属性解释如下:

  • android:exported ——此broadcastReceiver能否接收其他App的发出的广播,这个属性默认值有点意思,其默认值是由receiver中有无intent-filter决定的,如果有intent-filter,默认值为true,否则为false。(同样的,activity/service中的此属性默认值一样遵循此规则)同时,需要注意的是,这个值的设定是以application或者application user id为界的,而非进程为界(一个应用中可能含有多个进程);

  • ndroid:name —— 此broadcastReceiver类名;

  • android:permission ——如果设置,具有相应权限的广播发送方发送的广播才能被此broadcastReceiver所接收;

  • android:process ——broadcastReceiver运行所处的进程。默认为app的进程。可以指定独立的进程(Android四大基本组件都可以通过此属性指定自己的独立进程)

  • intent-filter ——用于指定此广播接收器接收特定的广播类型

静态注册样例:

<receiver android:name=".broadcast.BroadcastDemo"><intent-filter ><action android:name="android.intent.action.ACTION_POWER_CONNECTED"></action></intent-filter>
</receiver>

可能有的同学还有这个印象,通过静态注册广播,即使应用退出了,广播接收器依然还在工作,收到相应广播后还会处理,但是Android 3.1开始,系统在Intent与广播相关的flag增加了参数,分别是

FLAG_INCLUDE_STOPPED_PACKAGES:包含已经停止的包(停止:即包所在的进程已经退出)FLAG_EXCLUDE_STOPPED_PACKAGES:不包含已经停止的包

系统本身则增加了对所有app当前是否处于运行状态的跟踪。在发送广播时,不管是什么广播类型,系统默认直接增加了值为FLAG_EXCLUDE_STOPPED_PACKAGES的flag,导致即使是静态注册的广播接收器,对于其所在进程已经退出的app,同样无法接收到广播

动态注册样例

BroadcastDemo broadcastDemo = new BroadcastDemo();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com,mangoer.boradcast");
registerReceiver(broadcastDemo,intentFilter)

其中BoradcastDemo是我自定义的一个广播,给这个广播加了一个过滤器IntentFilter,表示这个广播接收器只接受这个类型的广播。注册之后一定要记得取消注册

if (broadcastDemo != null) {unregisterReceiver(broadcastDemo);
}

广播实现机制:

  1. 自定义广播接受者BroadcastReceiver,重写onReceive()方法
  2. 广播接受者通过Binder机制向AMS(Activity Manager Service)进行注册
  3. 广播发送者通过Binder向AMS发送广播
  4. AMS查找符合相应条件(Intent-filter或者permission)的BroadcastReceiver,将广播发送到BroadcastReceiver相应的消息队列中(通常是Activity的消息队列,即两者使用相同的Looper)
  5. 消息循环执行拿到此广播,回调BroadcastReceiver的onReceive方法

本地广播:

我们知道BroadcastReceiver设计的初衷就是从全局考虑,方便应用程序和系统程序之间、应用程序与应用程序之间、应用程序内部的通信;但是对于单个应用程序使用BroadcastReceiver是存在安全风险的:
如果别人通过反编译你的程序,获取到你的广播接收者的intent-filter或者permission,那就可以:

  1. 其它应用可以针对性的发出与当前应用intent-filter相匹配的广播,由此导致当前应用接收错误的数据,比如发送一个链接用来植入广告等
  2. 其它应用可以注册与当前应用一致的intent-filter,获取相关数据

解决方法如下:

  1. 对于同一App内部发送和接收广播,将exported属性设置成false,使得非本App内部发出的广播不被接收
  2. 在广播发送和接收时,都增加上相应的permission,用于权限验证
  3. 发送广播时,指定特定广播接收器所在的包名,具体是通过intent.setPackage(packageName)指定,这样此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中
  4. 使用LocalBroadcastManager,即本地广播,本地广播可以理解成一种局部广播的形式,广播的发送者和接收者都同属于一个App

使用本地广播优势:

  1. 使用它发送的广播只在APP内部传播,不必担心泄露数据
  2. 其它APP无法对你的APP发送伪造广播,不用担心有安全漏洞被利用
  3. 比通过系统发送全局广播更有效。

本地广播源码解析:

LocalBroadcastManager的构造方法

	private static LocalBroadcastManager mInstance;public static LocalBroadcastManager getInstance(Context context) {synchronized (mLock) {if (mInstance == null) {mInstance = new LocalBroadcastManager(context.getApplicationContext());}return mInstance;}}private LocalBroadcastManager(Context context) {mAppContext = context;mHandler = new Handler(context.getMainLooper()) {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_EXEC_PENDING_BROADCASTS:executePendingBroadcasts();break;default:super.handleMessage(msg);}}};}

从这些代码可以总结到:

  1. LocalBroadcastManager使用了单例模式,并且把外部传入的Context转化成了ApplicationContext,避免造成内存泄漏
  2. 在构造方法中创建了一个Handler,可见 LocalBroadcastManager的本质上是通过Handler机制发送和接收消息的。
  3. 在创建Handler的时候,使用了context.getMainLooper(),说明这个Handler是在UI线程创建的,即广播接收者是在主线程接收消息,所以开发者不能在onReceive方法中做耗时操作

LocalBroadcastManager的数据结构

private final HashMap<BroadcastReceiver, ArrayList<IntentFilter>> mReceivers= new HashMap<BroadcastReceiver, ArrayList<IntentFilter>>();
private final HashMap<String, ArrayList<ReceiverRecord>> mActions= new HashMap<String, ArrayList<ReceiverRecord>>();
private final ArrayList<BroadcastRecord> mPendingBroadcasts= new ArrayList<BroadcastRecord>();
  1. mReceivers是一个Map,key是开发者注册的广播接收者,value是每个BroadcastReceiver的多个IntentFileter组成的List
  2. mActions也是一个Map,key是IntentFilter中的action,value是ReceiverRecord组成的List;ReceiverRecord是一个内部类,维护了IntentFilter和BroadcastReceiver,记录了广播接收者,可以理解为 广播接收器记录者
  3. mPendingBroadcasts是一个List,保存了BroadcastRecord,这也是一个内部类,里面维护了Intent和ReceiverRecord的List集合;也就是把广播发送者发送的数据和对应的广播接收器封装成BroadcastRecord;可以理解为 广播待发送记录者

广播注册方法:

public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {synchronized (mReceivers) {//构建广播接收器记录者,包含过滤条件和广播接收器ReceiverRecord entry = new ReceiverRecord(filter, receiver);//构建保存过滤条件的集合ArrayList<IntentFilter> filters = mReceivers.get(receiver);if (filters == null) {filters = new ArrayList<IntentFilter>(1);//将每个广播接收器和对应的过滤条件进行映射mReceivers.put(receiver, filters);}//保存过滤条件filters.add(filter);for (int i=0; i<filter.countActions(); i++) {//将每个过滤条件对象的action取出String action = filter.getAction(i);//构建保存 广播接收器记录者 的集合ArrayList<ReceiverRecord> entries = mActions.get(action);if (entries == null) {//将ArrayList容量设置为1,节约内存,不过容量还是会随着元素增加自增长entries = new ArrayList<ReceiverRecord>(1);//将action和广播接收器记录者 进行映射mActions.put(action, entries);}//保存 广播接收器记录者//注意这里entries会添加重复的entryentries.add(entry);}}}

这个注册方法主要就是将广播接收者和过滤条件保存在mReceivers和mActions中

广播解除注册方法

public void unregisterReceiver(BroadcastReceiver receiver) {synchronized (mReceivers) {//从mReceivers集合移除该广播接收器,并取出对应的过滤条件集合ArrayList<IntentFilter> filters = mReceivers.remove(receiver);if (filters == null) {return;}for (int i=0; i<filters.size(); i++) {//取出过滤条件IntentFilter filter = filters.get(i);for (int j=0; j<filter.countActions(); j++) {//取出每个过滤条件对应的actionString action = filter.getAction(j);//从mActions取出每个action对应的 广播接收器记录者 集合,然后将集合清空ArrayList<ReceiverRecord> receivers = mActions.get(action);if (receivers != null) {for (int k=0; k<receivers.size(); k++) {//将从广播接收器记录者中取出的广播接收器与当前要//解除注册的广播接收器进行比较,如果相同,就移除if (receivers.get(k).receiver == receiver) {receivers.remove(k);k--;}}if (receivers.size() <= 0) {//从mActions中移除与当前广播接收器对应的action符合的广播接收器记录者 集合mActions.remove(action);}}}}}}

解除注册也就是把之前保存的数据清空

发送广播方法

public boolean sendBroadcast(Intent intent) {synchronized (mReceivers) {//从intent中取出actionfinal String action = intent.getAction();final String type = intent.resolveTypeIfNeeded(mAppContext.getContentResolver());final Uri data = intent.getData();final String scheme = intent.getScheme();final Set<String> categories = intent.getCategories();//从mActions集合中通过Intent中的action取出 广播接收器记录者 集合ArrayList<ReceiverRecord> entries = mActions.get(intent.getAction());if (entries != null) {//保存要处理该Intent的广播接收器记录者ArrayList<ReceiverRecord> receivers = null;for (int i=0; i<entries.size(); i++) {//取出每个 广播接收器记录者ReceiverRecord receiver = entries.get(i);//如果已经保存过了就跳过,因为注册方法中提到过entries可能会添加相同的ReceiverRecordif (receiver.broadcasting) {continue;}//将广播接收器记录者中维护的过滤条件与当前Intent进行比较int match = receiver.filter.match(action, type, scheme, data,categories, "LocalBroadcastManager");if (match >= 0) {if (receivers == null) {receivers = new ArrayList<ReceiverRecord>();}//如果能匹配到就将该 广播接收器记录者 保存到新的集合receivers.add(receiver);//表示 该广播接收器记录者 已经添加过了receiver.broadcasting = true;} }if (receivers != null) {//将新的集合遍历,把broadcasting置否,以便于下次开发者继续发送广播for (int i=0; i<receivers.size(); i++) {receivers.get(i).broadcasting = false;}//将广播待发送记录者保存在mPendingBroadcastsmPendingBroadcasts.add(new BroadcastRecord(intent, receivers));//判断是否在处理广播消息,没有就发送消息,让handler处理if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);}return true;}}}return false;}

发送广播逻辑:

  1. 过滤:将开发者传进来的Intent与已经保存注册的BroadcastReceiver的IntentFilter进行匹配
  2. 保存:将筛选出来的Intent和与其符合的BroadcastReceiver保存到mPendingBroadcasts集合中
  3. 发送消息让Handler去处理

将发送的Intent回调给广播接收器

private LocalBroadcastManager(Context context) {mAppContext = context;mHandler = new Handler(context.getMainLooper()) {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_EXEC_PENDING_BROADCASTS:executePendingBroadcasts();break;default:super.handleMessage(msg);}}};}private void executePendingBroadcasts() {while (true) {BroadcastRecord[] brs = null;synchronized (mReceivers) {//没有需要处理的Intent,就returnfinal int N = mPendingBroadcasts.size();if (N <= 0) {return;}//实例化BroadcastRecord数组,并且将mPendingBroadcasts中的数据添加到其中brs = new BroadcastRecord[N];mPendingBroadcasts.toArray(brs);mPendingBroadcasts.clear();}for (int i=0; i<brs.length; i++) {//取出每个广播待发送记录者BroadcastRecord br = brs[i];for (int j=0; j<br.receivers.size(); j++) {//取出 广播待发送记录者 中维护的 广播接收器记录者 集合//再取出 广播接收器记录者 集合中的广播接收器//再回调广播接收器的onReceive方法br.receivers.get(j).receiver.onReceive(mAppContext, br.intent);}}}
}

主要是通过构造方法中实例化的Handler来处理消息;每发送一次广播,就通过Handler发送一次消息处理,将Intent回调给对应的BroadcastRecevier的onReceive处理

本地广播总结:

  • LocalBroadcastManager高效的原因主要是因为它内部是通过Handler实现的,它的sendBroadcast发送广播与其它广播发送不一样,是使用Handler发送Message实现
  • 隔离其它APP广播的原因是因为本地广播是由Hnadler实现,不同应用(即不同进程)之间的内存块是相隔离的,不能直接访问,所以别的应用无法向我们的应用发送广播,我们发送的广播别的应用也不会收到
  • LocalBroadcastManager通过mReceivers集合将BroadcastRecevier与自己的IntentFilter做映射进行保存;通过mActions集合将action和封装了IntentFilter与BroadcastReceiver的ReceiverRecord做映射进行保存;通过mPendingBroadcasts集合保存BroadcastRecord,也就是把Intent和对应的BroadcastReceiver保存起来;最后在Handler里取出mPendingBroadcasts中的BroadcastReceiver,通过它的onReceive方法把Intent回调给它
  • BroadcastReceiver的通信是基于Binder机制,而LocalBroadcastManager的核心是基于Handler机制

本地广播与全局广播发送方法比较

本地广播

LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
BroadcastDemo broadcastDemo = new BroadcastDemo();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com,mangoer.boradcast");
broadcastManager.registerReceiver(broadcastDemo,intentFilter);broadcastManager.unregisterReceiver(broadcastDemo);

全局广播

BroadcastDemo broadcastDemo = new BroadcastDemo();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com,mangoer.boradcast");
Context.registerReceiver(broadcastDemo,intentFilter);Context.unregisterReceiver(broadcastDemo);

BroadcastReceiver接收顺序

  • 使用Context.sendBroadcast发送,如果依次注册了三个广播接收者A/B/C,那么接受顺序是C/B/A,即后注册的总是先收到广播
  • 使用LocalBroadcastManager.sendBroadcast发送,如果依次注册了三个广播接收者A/B/C,那么接受顺序是A/B/C,即先注册的总是先收到广播

广播发送方法

  • sendBroadcast(Intent intent);

    参数intent:携带Action标识信息(与注册广播是的IntentFilter中的action要相同)且可以携带数据

  • sendBroadcast(Intent intent, String receiverPermission)

    参数intent:携带Action标识信息(与注册广播是的IntentFilter中的action要相同)且可以携带数据

    参数receiverPermission:字面意思是指定广播接收者的权限,也就是说你的BroadcastReceiver注册的时候要添加了这个权限,后续才能收到这个广播

这篇关于Android广播--BroadcastReceiver 本地广播LocalBroadcastManager 8.0删除静态广播行为的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/279987

相关文章

电脑桌面文件删除了怎么找回来?别急,快速恢复攻略在此

在日常使用电脑的过程中,我们经常会遇到这样的情况:一不小心,桌面上的某个重要文件被删除了。这时,大多数人可能会感到惊慌失措,不知所措。 其实,不必过于担心,因为有很多方法可以帮助我们找回被删除的桌面文件。下面,就让我们一起来了解一下这些恢复桌面文件的方法吧。 一、使用撤销操作 如果我们刚刚删除了桌面上的文件,并且还没有进行其他操作,那么可以尝试使用撤销操作来恢复文件。在键盘上同时按下“C

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Thymeleaf:生成静态文件及异常处理java.lang.NoClassDefFoundError: ognl/PropertyAccessor

我们需要引入包: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>sp

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR