Android广播的学习和使用
1.引子
最近开发碰到一个需求,客户的设备是自助售货机,他们要求应用静默安装后能够启动,因为派人去现场一个个点击打开应用不现实。作为论坛复制粘贴工程师,碰到这个需求第一时间就是去网上搜索,看看这种需求有什么解决方案,网上文章很多,都说用静态广播,但我复制他们的代码一直没效果,反复排查哪里漏复制了,结果都不是,而是因为,这里先卖个关子,先学习一下广播,不然复制粘贴后还是啥都不懂。
2.广播定义
Android里的广播,和我们日常里的广播是相似的,都是用于消息的传递,但消息的传递不是一对一的传递,而是多对多的传递,这种模式称之为发布-订阅模式,发布者有很多,每个发布者都可以广播,不关心具体订阅者都是谁,订阅者有很多,每个订阅者只关心自己感兴趣的广播。举个例子,校园广播站每到放学时间打开广播,播放音乐、校园新闻等,这些不是发给特定的人,而是面向整个学校的师生,同样,听广播的师生,只挑感兴趣的广播注意收听,其他的不管,同时也不关心是谁在播放广播。
3.广播模型
发布-订阅模式有两个角色,分别是广播发布者和广播接收者,但在Android系统中,还有一个消息中心(Activity Manager Service)用于广播发分发。
不同的广播发布者往消息中心添加消息,众多的广播接收者需要先跟消息中心注册,告诉消息中心当有特点类型广播消息到达时,就通知它,这个过程是异步的,这样广播发布者和广播接收者是解耦的,不需要知道对方的存在,不需要双方同时在线。
4.广播的使用
4.1 广播的发送
广播发布者有系统也有应用,如果是系统,由系统自己发送广播,系统时刻在关注着系统内发生的各类事件,它就像一个爱八卦,当检测到下表总结的事件发生时,就将这些事件广播出去,例如系统启动完成,它会通过广播形式告诉大家我启动完成啦,当有应用安装时,它也同样发一个全局的广播,有新的应用入住啦。
系统操作 | action |
---|---|
监听网络变化 | android.net.conn.CONNECTIVITY_CHANGE |
关闭或打开飞行模式 | Intent.ACTION_AIRPLANE_MODE_CHANGED |
充电时或电量发生变化 | Intent.ACTION_BATTERY_CHANGED |
电池电量低 | Intent.ACTION_BATTERY_LOW |
电池电量充足(即从电量低变化到饱满时会发出广播 | Intent.ACTION_BATTERY_OKAY |
系统启动完成后(仅广播一次) | Intent.ACTION_BOOT_COMPLETED |
按下照相时的拍照按键(硬件按键)时 | Intent.ACTION_CAMERA_BUTTON |
屏幕锁屏 | Intent.ACTION_CLOSE_SYSTEM_DIALOGS |
设备当前设置被改变时(界面语言、设备方向等) | Intent.ACTION_CONFIGURATION_CHANGED |
插入耳机时 | Intent.ACTION_HEADSET_PLUG |
未正确移除SD卡但已取出来时(正确移除方法:设置–SD卡和设备内存–卸载SD卡) | |
插入外部储存装置(如SD卡) | Intent.ACTION_MEDIA_CHECKING |
成功安装APK | Intent.ACTION_PACKAGE_ADDED |
成功删除APK | Intent.ACTION_PACKAGE_REMOVED |
重启设备 | Intent.ACTION_REBOOT |
屏幕被关闭 | Intent.ACTION_SCREEN_OFF |
屏幕被打开 | Intent.ACTION_SCREEN_ON |
关闭系统时 | Intent.ACTION_SHUTDOWN |
重启设备 | Intent.ACTION_REBOOT |
如果广播发布者是应用,则通过Intent发送自定义的广播,如下是发送一个自定义的广播
Intent intent = new Intent();intent.setAction("com.example.broadcast.MY_NOTIFICATION");intent.putExtra("data","Notice me");sendBroadcast(intent);
4.2 广播的接收
和广播发送不同,广播接收稍微复杂一点,因为广播接收需要接收者先跟消息中心注册,注册又分为两大类,分别是静态注册和动态注册。
4.2.1 静态注册
A. 定义一个广播类
继承BroadcastReceiver定义一个广播类,重写onRecevie回调方法,onReceieve回调方法中是我们想要广播接收器收到广播之后需要处理的操作
public class mBroadcastReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {//在这里写上相关的处理代码,注意,不要此添加过多的逻辑或者是进行任何的耗时操作,过多操作会导致ANR}
}
B. 在AndroidManifest.xml里通过标签声明上一步定义的广播类
<receiver android:name=".mBroadcastReceiver" >//用于应用安装发出的广播<intent-filter><action android:name="android.intent.action.PACKAGE_ADDED" /> <data android:scheme="package" /> </intent-filter>
</receiver>
这就完成了静态注册,其中,用于设置我们感兴趣的广播。需要注意的是,这段代码在Android8.0及以上并不能正常接收到应用安装的广播!!运行代码会报Background execution not allowed-PACKAGE_ADDED
的错误,因为从 Android 8.0(API 级别 26)开始,出于限制后台启动的作用,系统对清单声明的接收器施加了额外的限制,大多数隐式广播(没有明确针对您的应用的广播)不能通过静态注册接收,静态注册仍可以接收的我们应用自定义的指定包名的广播,以及豁免的广播(见豁免广播类型)
不过,虽然静态注册不能接收到这些广播,但动态注册不受影响,因此为了正常接收广播,可通过动态注册的方式。
4.2.2 动态注册
所谓的动态注册,是指在代码中调用Context.registerReceiver()
方法,整体步骤如下:
- 仍和静态注册一样,需要定义一个广播类,然后在相关的activity中实例化;
- new一个
intentFilter
类,调用其的setAction方法,参数中传入相关值的action,用于设置感兴趣的广播类型; - 调用
context.registerReceiver
方法进行注册,方法的第一个参数为广播类,第二个则是intentFilter类
private mBroadcastReceiver mbroadcastReceiver;
private IntentFilter intentFilter;
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mbroadcastReceiver = new mBroadcastReceiver();intentFilter = new IntentFilter();intentFilter.addAction("android.intent.action.PACKAGE_ADDED");intentFilter.addDataScheme("package");registerReceiver(mbroadcastReceiver,intentFilter);
}
需要注意的是,动态注册的广播接收器一定要注销,在onDestroy方法中调用unregisterReceiver(mbroadcastReceiver)
完成注销,否则会报内存泄露错误。
5.总结
首先回答引子里的问题,为什么静态注册无法接收应用安装广播,因为Android 8.0对这类广播做了限制。广播的使用算是四大组件里使用较简单的一种,当时复制粘贴其他博客写的代码后总是无法正常接收广播时,不相信使用如此简单,一直怀疑是不是遗漏了什么,当学习一遍广播时还真是如此,特别是静态注册,不过Android 8.0以后静态注册也不好使,被限制了很多。
Android广播的学习和使用相关推荐
- Android广播机制:Broadcast
转载:Android总结篇系列:Android广播机制 1.Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广 ...
- Android音视频学习系列(五) — 掌握音频基础知识并使用AudioTrack、OpenSL ES渲染PCM数据
系列文章 Android音视频学习系列(一) - JNI从入门到精通 Android音视频学习系列(二) - 交叉编译动态库.静态库的入门 Android音视频学习系列(三) - Shell脚本入门 ...
- Android基础知识点学习总结
Android基础知识点学习总结 安卓基础知识个人学习笔记分享~ 一.Android系统架构 Linux内核层→系统运行层→应用框架层→应用层 1.Linux内核层:Android系统是基于Linux ...
- Android 广播实现原理解析
Android 广播实现原理解析 前言 Android四大组件中的BroadcastReceiver,在我们实际工作中被频繁的使用,我们可以利用系统的开机广播,网络状态改变的广播等等实现我们的业务逻辑 ...
- Android插件化学习之路(一)之动态加载综述
前段时间,公司项目完成了插件化的开发,自己也因此学习了很多Android插件化的知识,于是想把这些内容记录下来,本次带来Android插件化的第一篇:动态加载综述 Android插件化学习之路(一)之 ...
- 2021年超详细的-Android超神学习路线总结--纯干货分享(字节,阿里,腾讯大牛联合打造)
前言 2021年秋招没有找到满意工作的童鞋,考研结果不理想的童鞋,留学生回国的童鞋们,都开始准备2021年的春招了,如果想从事Android开发工作,可以参考本文. 本文整理了Android开发的学习 ...
- Android音视频学习系列(六) — 掌握视频基础知识并使用OpenGL ES 2.0渲染YUV数据
系列文章 Android音视频学习系列(一) - JNI从入门到精通 Android音视频学习系列(二) - 交叉编译动态库.静态库的入门 Android音视频学习系列(三) - Shell脚本入门 ...
- Android 应用开发学习笔记(2 of 2,from hitwh)
Android 应用开发 注意!由于文章图片是通过typora一键上传图片实现,该功能还存在bug,容易导致图片顺序混乱,文章(1 of 2)开头提供了原版文章的 pdf 资源下载,推荐下载 pdf ...
- 基于 Android NDK 的学习之旅-----资源释放
基于 Android NDK 的学习之旅-----资源释放 做上一个项目的时候因为与C引擎交互频繁,有时候会突然莫名其妙的的整个应用程序直接挂掉.因为我是学Java 开始的,所以对主动释放内存没多大概 ...
最新文章
- python验证用户登录的判断_python怎么判断用户是否登录?
- SpringMVC下的基本配置
- Redis Sentinel集群部署
- 马斯克终于承认售出比特币:卖了10%
- ifen.os x pe.dmg天翼云_3.3K屏显纵览天下 11代酷睿横行职场 华硕灵耀X纵横值得选择...
- MSMQ 和 MQTT
- js页面间通信方法实现
- Python进行停用词表去重
- eeprom和编程器固件 k2_斐讯K2编程器刷breed换固件小白教程
- Matlab入门:界面认识
- 逻辑学是计算机 创始人,逻辑学的创始人:亚里士多德
- 《蜗居》的经典台词(转载)二
- Python员工信息作业
- Mongoose第三方包常用操作整理
- SHELL对接国际验证码接口
- 字符集本地化(locale)与输入法系列讲座-----(3) truetype造字程序详解
- 健康地奋斗着——程序员自己的养生书
- Linux设备驱动-platform虚拟总线dya02
- 网络空间安全 知识图谱的构建与应用(一)
- ERROR:error opening DLL Library错误的一个原因
热门文章
- boost::mp11::mp_eval_if_not_q相关用法的测试程序
- boost::geometry::index::intersects用法的测试程序
- boost::fusion::zip_view用法的测试程序
- GDCM:MrProtocol的测试程序
- boost::coroutine模块实现不对称链的测试程序
- boost::first_scalar的测试程序
- VTK:Qt之ShareCameraQt
- VTK:几何对象之Dodecahedron
- Qt Creator添加套件
- C语言Kruskal 算法 (MST)(附完整源码)