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()方法,整体步骤如下:

  1. 仍和静态注册一样,需要定义一个广播类,然后在相关的activity中实例化;
  2. new一个intentFilter类,调用其的setAction方法,参数中传入相关值的action,用于设置感兴趣的广播类型;
  3. 调用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广播的学习和使用相关推荐

  1. Android广播机制:Broadcast

    转载:Android总结篇系列:Android广播机制 1.Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广 ...

  2. Android音视频学习系列(五) — 掌握音频基础知识并使用AudioTrack、OpenSL ES渲染PCM数据

    系列文章 Android音视频学习系列(一) - JNI从入门到精通 Android音视频学习系列(二) - 交叉编译动态库.静态库的入门 Android音视频学习系列(三) - Shell脚本入门 ...

  3. Android基础知识点学习总结

    Android基础知识点学习总结 安卓基础知识个人学习笔记分享~ 一.Android系统架构 Linux内核层→系统运行层→应用框架层→应用层 1.Linux内核层:Android系统是基于Linux ...

  4. Android 广播实现原理解析

    Android 广播实现原理解析 前言 Android四大组件中的BroadcastReceiver,在我们实际工作中被频繁的使用,我们可以利用系统的开机广播,网络状态改变的广播等等实现我们的业务逻辑 ...

  5. Android插件化学习之路(一)之动态加载综述

    前段时间,公司项目完成了插件化的开发,自己也因此学习了很多Android插件化的知识,于是想把这些内容记录下来,本次带来Android插件化的第一篇:动态加载综述 Android插件化学习之路(一)之 ...

  6. 2021年超详细的-Android超神学习路线总结--纯干货分享(字节,阿里,腾讯大牛联合打造)

    前言 2021年秋招没有找到满意工作的童鞋,考研结果不理想的童鞋,留学生回国的童鞋们,都开始准备2021年的春招了,如果想从事Android开发工作,可以参考本文. 本文整理了Android开发的学习 ...

  7. Android音视频学习系列(六) — 掌握视频基础知识并使用OpenGL ES 2.0渲染YUV数据

    系列文章 Android音视频学习系列(一) - JNI从入门到精通 Android音视频学习系列(二) - 交叉编译动态库.静态库的入门 Android音视频学习系列(三) - Shell脚本入门 ...

  8. Android 应用开发学习笔记(2 of 2,from hitwh)

    Android 应用开发 注意!由于文章图片是通过typora一键上传图片实现,该功能还存在bug,容易导致图片顺序混乱,文章(1 of 2)开头提供了原版文章的 pdf 资源下载,推荐下载 pdf ...

  9. 基于 Android NDK 的学习之旅-----资源释放

    基于 Android NDK 的学习之旅-----资源释放 做上一个项目的时候因为与C引擎交互频繁,有时候会突然莫名其妙的的整个应用程序直接挂掉.因为我是学Java 开始的,所以对主动释放内存没多大概 ...

最新文章

  1. python验证用户登录的判断_python怎么判断用户是否登录?
  2. SpringMVC下的基本配置
  3. Redis Sentinel集群部署
  4. 马斯克终于承认售出比特币:卖了10%
  5. ifen.os x pe.dmg天翼云_3.3K屏显纵览天下 11代酷睿横行职场 华硕灵耀X纵横值得选择...
  6. MSMQ 和 MQTT
  7. js页面间通信方法实现
  8. Python进行停用词表去重
  9. eeprom和编程器固件 k2_斐讯K2编程器刷breed换固件小白教程
  10. Matlab入门:界面认识
  11. 逻辑学是计算机 创始人,逻辑学的创始人:亚里士多德
  12. 《蜗居》的经典台词(转载)二
  13. Python员工信息作业
  14. Mongoose第三方包常用操作整理
  15. SHELL对接国际验证码接口
  16. 字符集本地化(locale)与输入法系列讲座-----(3) truetype造字程序详解
  17. 健康地奋斗着——程序员自己的养生书
  18. Linux设备驱动-platform虚拟总线dya02
  19. 网络空间安全 知识图谱的构建与应用(一)
  20. ERROR:error opening DLL Library错误的一个原因

热门文章

  1. boost::mp11::mp_eval_if_not_q相关用法的测试程序
  2. boost::geometry::index::intersects用法的测试程序
  3. boost::fusion::zip_view用法的测试程序
  4. GDCM:MrProtocol的测试程序
  5. boost::coroutine模块实现不对称链的测试程序
  6. boost::first_scalar的测试程序
  7. VTK:Qt之ShareCameraQt
  8. VTK:几何对象之Dodecahedron
  9. Qt Creator添加套件
  10. C语言Kruskal 算法 (MST)(附完整源码)