文章目录
- 广播机制
- 广播机制简介
- 标准广播
- 有序广播
- 接收系统广播
- 动态注册监听时间变化
- 动态注册示例
- 静态注册时间开机启动
- 静态注册示例
广播机制
广播机制简介
- Android中每个应用程序都可以对自己感兴趣的广播进行注册,这样程序就只会受到自己关注的广播了.
- 广播有可能是来自系统的,也有可能是来自其他应用程序的
- Andorid中提供了一套完整的API,允许应用程序自由完整的发送和接收广播
- 广播主要分为:标准广播和有序广播
标准广播
- 标准广播:完全异步执行的广播,在广播发送出之后,所有的BroadcastReceiver几乎会在同一时刻收到这条广播的消息,同时也意味着他是无法截断的.
- 标准广播的流程图:
有序广播
- 有序广播:是一种同步执行的广播,在广播发出之后,同一时刻只会有一个BroadcastReceiver能够收到这一条广播消息,当这个BroadcastReceiver中的逻辑执行完毕之后,广播才会继续传递,所以此时BroadcastReceiver实际上是有顺序的.
- 优先级高的BroadcastReceiver会先收到广播消息,并且前面的BroadcastReceiver还可以截断正在传递的广播,这样后面的BroadcastReceiver就无法收到广播消息了.
- 有序广播的流程图
接收系统广播
- 在Android内置了很多的系统广播,我们可以在应用程序中通过监听这些广播来得到各种系统状态信息.
- 如果想要接收到一条广播信息,就需要使用到BroadcastReceiver
动态注册监听时间变化
- 我们可以根据自己感兴趣的广播,自由的注册BroadcastReceiver,这样当有相应的广播发出通知的时候,相应的BroadcastReceiver就能够接收到广播了.
- 并且可以在内部进行逻辑处理.
- 注册BroadcastReceiver的方式一般有两种:在代码中注册和AndroidManifest.xml中进行注册
- 在代码当中注册被称为动态注册,在AndroidManifest.xml中注册被称为静态注册
- 创建一个BroadcastReceiver只需要编写一个类,让他继承自BroadcastReceiver,然后重写父类的onReceive()方法,这样当有广播来到的时候,onRecive()方法就会得到执行,具体的逻辑就可以在这个方法当中处理.
动态注册示例
- 使用动态注册实现一个能够监听时间变化的程序
- 创建一个BroadcastTest项目
- 在MainActivity中创建一个TimeChangeReceiver内部类让这个内部类继承自BroadcastReceiver
- 然后重写BroadcastReceiver的onReceive()方法,然后在这个方法当中编写具体的逻辑
- 在onCreate()方法中编写注册的逻辑
package com.zb.broadcasttest
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
class MainActivity : AppCompatActivity() {
lateinit var timeChangeReceiver: TimeChangeReceiver
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//创建一个IntentFilter实例
val intentFilter = IntentFilter()
//给IntentFilter实例添加一个值为"android.intent.action.TIME_TICK"的acton
//表示系统发出的正是一条值为"android.intent.action.TIME_TICK"的广播
//也就是说我们的BroadcastReceiver想要简单的是什么广播,就在这里添加什么的action
intentFilter.addAction("android.intent.action.TIME_TICK")
//创建一个TimeChangeReceiver的实例
timeChangeReceiver = TimeChangeReceiver()
//调用registerReceiver()方法进行注册
registerReceiver(timeChangeReceiver, intentFilter)
//这样TimeChangeReceiver就会接收到所有值为"android.intent.action.TIME_TICK"的广播了,也就是是实现了监听了系统时间变化的功能
}
override fun onDestroy() {
super.onDestroy()
//需要注意的是,动态注册的BroadcastReceiver一定要记得取消注册
unregisterReceiver(timeChangeReceiver)
}
//定义一个内部类TimeChangeReceiver内部类
inner class TimeChangeReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
//简单使用Toast提示一段文本信息
Toast.makeText(context, "Time has change", Toast.LENGTH_SHORT).show()
}
}
}
- 这里是接收系统时间变化广播的基本方式,接受其他系统广播的用法也是如此
- Android系统还会在亮屏息屏,电量变化,网络变化等场景下发出广播
- 查看完整的系统广播列表可以在下面路径中进行查看:
<Android SDK>/platforms/<任意 android api 版本>/data/broadcast_actions.txt
静态注册时间开机启动
- 动态注册BroadcastReceiver可以自由地控制注册和注销,比较具有灵活性
- 但是存在一个缺点就是,必须在程序启动之后才能接收广播,因为注册的逻辑是写在onCreate()方法中的.
- 当我们需要让程序在未启动的情况下依然可以接收广播,我们就可以使用到静态注册的方式
- 在之前动态注册能够接受的广播,静态注册也同样可以进行接收,但是由于大量的恶意应用利用这个机制在程序未启动的情况下监听系统广播,从而使任何应用都可以从后台被唤醒,从而影响了用户手机的电量和性能
- 因此每个版本的Android系统都在削弱这个静态注册的功能
- 在安卓8.0版本之后的系统,所有的隐式广播都不允许使用静态注册的方式进行注册了
- 隐式广播指的是没有具体指定发送给哪个应用程序的广播,而大多数的广播都属于是隐式广播
- 目前只有少部分特殊的广播支持静态注册的方式来接收
- 这些特殊的广播可以列表可以参考:
- 隐式广播例外情况 | Android 开发者 | Android Developers (google.cn)
- 其中有一条为开机广播:
android.intent.action.BOOT_COMPLETED
静态注册示例
- 上个示例使用了内部类的方式创建了BroadcastReceiver,其实还可以使用编译器的快捷方式进行创建
package com.zb.broadcasttest
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.widget.Toast
class BootCompleteReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Toast.makeText(context, "Boot complete", Toast.LENGTH_SHORT).show()
}
}
- 使用静态注册的BroadcastRecevier一定要在AndroidManifest.xml中进行注册才可以使用
- 但是由于使用了AS快捷方式进行注册,所以这一步可以进行省略
- 但是此时BootCompleteReceiver是无法收到开机广播的,还需要在AndroidManifest.xml中做一下修改
- 安卓系统为了保护用户设备的安全隐私,做了严格的规定
- 如果程序需要进行一些比较敏感的操作,必须在AndroidManifest.xml文件中进行声明,否则程序会直接进行崩溃
- 上面的接收系统的开机广播就是需要进行权限声明的.所以在AndroidManifest.xml中使用
<uses-permission android:name="android.intent.action.BOOT_COMPLETED" />
- 来进行权限声明
- 目前只是在onReceive()方法当中使用Toast进行了简单提示,真正在项目开发当中可以在这个方法当中编写具体的逻辑,但是不能在onReceive()方法当中添加过多的逻辑代码或者进行任何耗时的操作,因为BroadcastReceiver中是不允许开线程的,当onReceive()方法运行时间比较长还没有结束的话,程序就会出现错误.