Andorid广播

news2024/11/25 19:40:18

以下内容摘自郭霖《第一行代码》第三版

文章目录

    • 一、广播机制简介
      • 1.1 广播的类型
        • 1.1.1 标准广播
        • 1.1.2 有序广播
    • 二、接收系统广播
      • 2.1 动态注册监听时间变化
      • 2.2 静态注册实现开机启动
    • 三、发送自定义广播
      • 3.1 发送标准广播
      • 3.2 发送有序广播

一、广播机制简介

1.1 广播的类型

Android中的广播主要可以分为两种类型:标准广播和有序广播。

1.1.1 标准广播

标准广播(normal broadcasts)是一种完全异步执行的广播,在广播发出之后,所有的BroadcastReceiver几乎会在同一时刻收到这条广播消息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,但同时也意味着它是无法被截断的。
在这里插入图片描述

1.1.2 有序广播

有序广播(ordered broadcasts)则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个BroadcastReceiver能够收到这条广播消息,当这个BroadcastReceiver中的逻辑执行完毕后,广播才会继续传递。所以此时的BroadcastReceiver是有先后顺序的,优先级高的BroadcastReceiver就可以先收到广播消息,并且前面的BroadcastReceiver还可以截断正在传递的广播,这样后面的BroadcastReceiver就无法收到广播消息了。
在这里插入图片描述

二、接收系统广播

2.1 动态注册监听时间变化

注册BroadcastReceiver的方式一般有两种:在代码中注册和在AndroidManifest.xml中注册。其中前者也被称为动态注册,后者也被称为静态注册。

class MainActivity : AppCompatActivity() {
	lateinit var timeChangeReceiver: TimeChangeReceiver
	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)
		setContentView(R.layout.activity_main)
		val intentFilter = IntentFilter()
		intentFilter.addAction("android.intent.action.TIME_TICK")
		timeChangeReceiver = TimeChangeReceiver()
		registerReceiver(timeChangeReceiver, intentFilter)
	}
	override fun onDestroy() {
		super.onDestroy()
		unregisterReceiver(timeChangeReceiver)
	}
	inner class TimeChangeReceiver : BroadcastReceiver() {
		override fun onReceive(context: Context, intent: Intent) {
			Toast.makeText(context, "Time has changed", Toast.LENGTH_SHORT).show()
		}
	}
}

观察onCreate()方法,首先我们创建了一个IntentFilter的实例,并给它添加了一个值为android.intent.action.TIME_TICK的action,因为当系统时间发生变化时,系统发出的正是一条值为android.intent.action.TIME_TICK的广播,也就是说BroadcastReceiver想要监听什么广播,就在这里添加相应的action。接下来创建了一个TimeChangeReceiver的实例,然后调用registerReceiver()方法进行注册,将TimeChangeReceiver的实例和IntentFilter的实例都传了进去,这样TimeChangeReceiver就会收到所有值为android.intent.action.TIME_TICK的广播,也就实现了监听系统时间变化的功能。

动态注册的BroadcastReceiver一定要取消注册才行,这里是在onDestroy()方法中通过调用unregisterReceiver()方法来实现的。

Android系统还会在亮屏熄屏、电量变化、网络变化等场景下发出广播。如果想查看完整的系统广播列表,可以到如下的路径中去查看:

<Android SDK>/platforms/<任意android api版本>/data/broadcast_actions.txt

2.2 静态注册实现开机启动

在Android 8.0系统之后,所有隐式广播都不允许使用静态注册的方式来接收了。隐式广播指的是那些没有具体指定发送给哪个应用程序的广播,大多数系统广播属于隐式广播,但是少数特殊的系统广播目前仍然允许使用静态注册的方式来接收。这些特殊的系统广播列表详见https://developer.android.google.cn/guide/components/broadcast-exceptions?hl=zh-cn。

class BootCompleteReceiver : BroadcastReceiver() {
	override fun onReceive(context: Context, intent: Intent) {
		Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show()
	}
}

静态的BroadcastReceiver一定要在AndroidManifest.xml文件中注册才可以使用。如果使用Android Studio的快捷方式创建BroadcastReceiver,注册这一步已经自动完成了。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="com.example.broadcasttest">
	<application
		android:allowBackup="true"
		android:icon="@mipmap/ic_launcher"
		android:label="@string/app_name"
		android:roundIcon="@mipmap/ic_launcher_round"
		android:supportsRtl="true"
		android:theme="@style/AppTheme">
		...
		<receiver
			android:name=".BootCompleteReceiver"
			android:enabled="true"
			android:exported="true">
		</receiver>
	</application>
</manifest>

不过目前的BootCompleteReceiver是无法收到开机广播的,因为没有进行授权,因此我们还需要对AndroidManifest.xml文件进行修改才行,添加授权:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="com.example.broadcasttest">
	<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
	<application
		android:allowBackup="true"
		android:icon="@mipmap/ic_launcher"
		android:label="@string/app_name"
		android:roundIcon="@mipmap/ic_launcher_round"
		android:supportsRtl="true"
		android:theme="@style/AppTheme">
		...
		<receiver
			android:name=".BootCompleteReceiver"
			android:enabled="true"
			android:exported="true">
			<intent-filter>
				<action android:name="android.intent.action.BOOT_COMPLETED" />
			</intent-filter>
		</receiver>
	</application>
</manifest>

Android 系统为了保护用户设备的安全和隐私,做了严格的规定:如果程序需要进行一些对用户来说比较敏感的操作,必须在AndroidManifest.xml文件中进行权限声明,否则程序将会直接崩溃。

注意:不要在onReceive()方法中添加过多的逻辑或者进行任何的耗时操作,因为BroadcastReceiver中是不允许开启线程的,当onReceive()方法运行了较长时间而没有结束时,程序就会出现错误。

三、发送自定义广播

3.1 发送标准广播

class MyBroadcastReceiver : BroadcastReceiver() {
	override fun onReceive(context: Context, intent: Intent) {
		Toast.makeText(context, "received in MyBroadcastReceiver",Toast.LENGTH_SHORT).show()
	}
}

然后在AndroidManifest.xml中对这个BroadcastReceiver进行修改:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="com.example.broadcasttest">
	...
	<application
		android:allowBackup="true"
		android:icon="@mipmap/ic_launcher"
		android:label="@string/app_name"
		android:roundIcon="@mipmap/ic_launcher_round"
		android:supportsRtl="true"
		android:theme="@style/AppTheme">
		...
		<receiver
			android:name=".MyBroadcastReceiver"
			android:enabled="true"
			android:exported="true">
			<intent-filter>
				<action android:name="com.example.broadcasttest.MY_BROADCAST"/>
			</intent-filter>
		</receiver>
	</application>
</manifest>
class MainActivity : AppCompatActivity() {
	...
	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)
		setContentView(R.layout.activity_main)
		button.setOnClickListener {
			val intent = Intent("com.example.broadcasttest.MY_BROADCAST")
			intent.setPackage(packageName)
			sendBroadcast(intent)
		}
		...
	}
	...
}

对第2步调用的setPackage()方法进行更详细的说明:在Android 8.0系统之后,静态注册的BroadcastReceiver是无法接收隐式广播的,而默认情况下发出的自定义广播恰恰都是隐式广播。因此这里一定要调用setPackage()方法,指定这条广播是发送给哪个应用程序的,从而让它变成一条显式广播,否则静态注册的BroadcastReceiver将无法接收到这条广播。

另外,由于广播是使用Intent来发送的,因此你还可以在Intent中携带一些数据传递给相应的BroadcastReceiver,这一点和Activity的用法是比较相似的

3.2 发送有序广播

和标准广播不同,有序广播是一种同步执行的广播,并且是可以被截断的。
新增AnotherBroadcastReceiver

class AnotherBroadcastReceiver : BroadcastReceiver() {
	override fun onReceive(context: Context, intent: Intent) {
		Toast.makeText(context, "received in AnotherBroadcastReceiver", Toast.LENGTH_SHORT).show()
	}
}

修改Manifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	 package="com.example.broadcasttest">
	 ...
	 <application
		 android:allowBackup="true"
		 android:icon="@mipmap/ic_launcher"
		 android:label="@string/app_name"
		 android:roundIcon="@mipmap/ic_launcher_round"
		 android:supportsRtl="true"
		 android:theme="@style/AppTheme">
		 ...
		 <receiver
			 android:name=".AnotherBroadcastReceiver"
			 android:enabled="true"
			 android:exported="true">
			 <intent-filter>
				 <action android:name="com.example.broadcasttest.MY_BROADCAST" />
			 </intent-filter>
		 </receiver>
	 </application>	
</manifest>

不过,到目前为止,程序发出的都是标准广播,现在我们来尝试一下发送有序广播。修改MainActivity中的代码,如下所示:

class MainActivity : AppCompatActivity() {
	...
	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)
		setContentView(R.layout.activity_main)
		button.setOnClickListener {
			val intent = Intent("com.example.broadcasttest.MY_BROADCAST")
			intent.setPackage(packageName)
			sendOrderedBroadcast(intent, null)
		}
		...
	}
	...
}

sendOrderedBroadcast()方法接收两个参数:第一个参数仍然是Intent;第二个参数是一个与权限相关的字符串,这里传入null就行了。
设定BroadcastReceiver的先后顺序:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="com.example.broadcasttest">
	...
	<application
		android:allowBackup="true"
		android:icon="@mipmap/ic_launcher"
		android:label="@string/app_name"
		android:roundIcon="@mipmap/ic_launcher_round"
		android:supportsRtl="true"
		android:theme="@style/AppTheme">
		...
		<receiver
			android:name=".MyBroadcastReceiver"
			android:enabled="true"
			android:exported="true">
			<intent-filter android:priority="100">
				<action android:name="com.example.broadcasttest.MY_BROADCAST"/>
			</intent-filter>
		</receiver>
		...
	</application>
</manifest>

通过android:priority属性给BroadcastReceiver设置了优先级,优先级比较高的BroadcastReceiver就可以先收到广播。这里将MyBroadcastReceiver的优先级设成了100,以保证它一定会在AnotherBroadcastReceiver之前收到广播。
既然已经获得了接收广播的优先权,那么MyBroadcastReceiver就可以选择是否允许广播继续传递了。修改MyBroadcastReceiver中的代码,如下所示:

class MyBroadcastReceiver : BroadcastReceiver() {
	override fun onReceive(context: Context, intent: Intent) {
		Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show()
		abortBroadcast()
	}
}

如果在onReceive()方法中调用了abortBroadcast()方法,就表示将这条广播截断,后面的BroadcastReceiver将无法再接收到这条广播。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/912613.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

EPS倾斜摄影模型测图

1、打开EPS软件&#xff0c;新建工程。 2、加载倾斜摄影模型。在三维测图--倾斜摄影--加载本地倾斜模型中&#xff0c;加载模型到工作空间。 3、加载后的结果如下&#xff1a; 4、开始绘制房屋。选择编码--进入加线模式--开始绘图。 开始绘图图形&#xff0c; 5、绘图按键使用 …

面试题大揭秘!Java中== 与equals的区别?

大家好&#xff0c;我是你们的小米&#xff01;今天我们要来聊一个在Java面试中经常被问到的问题&#xff1a; 与 equals 的区别。这可是一个重要而且常常令人头疼的问题哦&#xff01;废话不多说&#xff0c;咱们马上开启今天的探索之旅吧&#xff01; 背景知识 在开始深入探…

什么是雨量气象站?

过多的强降水会造成重大自然灾害&#xff0c;给我们的生活带来很大影响&#xff0c;实时监测降雨信息&#xff0c;能够及时发布气象预警&#xff0c;防范可能因强降水引起的山洪、泥石流等自然灾害&#xff0c;保护人民群众生命财产安全&#xff0c;提高防灾减灾能力。 雨量气…

【三维重建】【深度学习】NeuS代码Pytorch实现--测试阶段代码解析(下)

【三维重建】【深度学习】NeuS代码Pytorch实现–测试阶段代码解析(下) 论文提出了一种新颖的神经表面重建方法&#xff0c;称为NeuS&#xff0c;用于从2D图像输入以高保真度重建对象和场景。在NeuS中建议将曲面表示为有符号距离函数(SDF)的零级集&#xff0c;并开发一种新的体绘…

springboot+vue实现的智慧学校云平台源码

智慧校园源码 智慧班牌云平台源码 系统架构&#xff1a;Javavue2springbootMySQL elmentuiQuartzjpajwt 智慧校园电子班牌云平台是出于校园考勤管理以及班级校园信息展示为目的的管理系统&#xff0c;电子班牌系统主要用于中小学教育的综合管理平台&#xff0c;融合了多媒体技…

SPSS中级统计--卡方独立性检验之n×c表资料

nc资料表检验 nc资料表分类&#xff1a; ①双向无序的RC表资料 ②单向有序的RC表资料 ③双向有序的RC表资料 1、双向无序RC表资料 多个样本率的比较&#xff08;c2&#xff09; 例1&#xff1a;比较不同污染地区的动物畸形率是否有差异&#xff1f; H0&#xff1a;不同污染…

Android中使用JT808协议进行车载终端通信的实现和优化

JT808是一种在中国广泛应用的车载终端通信协议&#xff0c;用于车辆与监控中心之间的数据通信。下面是关于Android平台上使用JT808协议进行通信的一般步骤和注意事项&#xff1a; 协议了解&#xff1a;首先&#xff0c;您需要详细了解JT808协议的规范和定义。该协议包含了通信消…

iServer通过服务实例动态化管理MongoDB万级瓦片集应用实践

作者&#xff1a;Carlo 文章目录 数据特点项目难点优化方案先了解“服务实例动态化管理”功能特性“服务实例动态化管理”应用场景优化1&#xff1a;开启服务实例动态化管理优化2&#xff1a;同时设置一个特定服务关闭动态管理持续存活优化3&#xff1a;将服务配置信息存储到Po…

React(8)

千锋学习视频https://www.bilibili.com/video/BV1dP4y1c7qd?p72&spm_id_frompageDriver&vd_sourcef07a5c4baae42e64ab4bebdd9f3cd1b3 1.React 路由 1.1 什么是路由&#xff1f; 路由是根据不同的 url 地址展示不同的内容或页面。 一个针对React而设计的路由解决方案…

python从入门到精通——完整教程

阅读全文点击《python从入门到精通——完整教程》 一、编程入门与进阶提高 Python编程入门 1、Python环境搭建&#xff08; 下载、安装与版本选择&#xff09;。 2、如何选择Python编辑器&#xff1f;&#xff08;IDLE、Notepad、PyCharm、Jupyter…&#xff09; 3、Pytho…

安装npm和react

下载react 下载node链接 或者&#xff1a; https://nodejs.org/zh-cn/download/ 下载以后重启电脑&#xff08;刷新环境变量&#xff09; 或者手工刷新环境变量 检查环境变量 node -v npm -v如果没有问题应该是这两个&#xff1a; 修改镜像源 npm config set registry ht…

基于swing的在线考试系统java jsp线上试卷问答mysql源代码

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 基于swing的在线考试系统 系统有2权限&#xff1a;管…

第二篇:基础窗口部件 QWidget

基础窗口部件 QWidget QWidget 类是所有用户界面对象的基类&#xff0c;因此被称为基础窗口部件。QWidget 继承自 QObject 类和QPaintDevice 类&#xff0c;其中 QObject 类是所有支持 Qt 对象模型&#xff08;Qt Object Model&#xff09;的对象的基类&#xff0c;QPaintDevi…

LTD与杭州商务局系统签订战略合作协议:共同推动商贸企业数字化

LTD将继续发挥“营销SaaS系统场景应用”的优势&#xff0c;为做强做优做大我国数字经济贡献更多力量。 近日&#xff0c;由杭州市商务局指导&#xff0c;杭州市商务发展研究中心&#xff08;杭州市中小商贸流通企业服务中心&#xff09;主办&#xff0c;每日商报承办&#xff0…

【Vue3】 Vue-Router路由和路由导航守卫

路由 前后端分离阶段路由单页面富应用阶段前端路由如何做到URL和内容进行映射?URl的hash&#xff08;哈希&#xff09;URl的history Vue-Router基本使用1&#xff0c;安装Vue-Router2&#xff0c;新建页面router文件下的index.js,路由&#xff0c;导入页面&#xff0c;导入路由…

一定解决JavaFx运行时Application爆红色问题

文章目录 注意maven项目创建maven javafx项目配置 注意 以下的问题纯粹是因为新建的是普通项目&#xff0c;而不是Java FX项目&#xff0c;如果新建的是Java FX项目&#xff0c;那么idea会自动给你生成相应的需要的pom.xml文件&#xff0c;并且运行也是正常的 maven项目创建…

RPC和HTTP协议

RPC 全称&#xff08;Remote Procedure Call&#xff09;&#xff0c;它是一种针对跨进程或者跨网络节点的应用之间的远程过程调用协议。 它的核心目标是&#xff0c;让开发人员在进行远程方法调用的时候&#xff0c;就像调用本地方法一样&#xff0c;不需要额外为了完成这个交…

Rspack 创建 vue2/3 项目接入 antdv(rspack.config.js 配置 less 主题)

一、简介 Rspack CLI 官方文档。 rspack.config.js 官方文档。 二、创建 vue 项目 创建项目&#xff08;文档中还提供了 Rspack 内置 monorepo 框架 Nx 的创建方式&#xff0c;根据需求进行选择&#xff09; # npm 方式 $ npm create rspacklatest# yarn 方式 $ yarn create…

SSD基本工作原理了解

SSD与RAM的原理有些类似&#xff0c;RAM使用晶体管和电容来表示0或1&#xff0c;晶体管用于将电荷转移到电容器或从电容器中吸取电荷&#xff0c;并且电荷必须每几微秒刷新一次。 而SSD相比于RAM的非易失性来自于其使用的浮栅晶体管。其创造了一个小笼子&#xff0c;不需要外界…

Sui生态项目|集隐私通信、移动钱包、链上朋友圈和红包功能一体的社交应用ComingChat

ComingChat是在Sui网络上构建的去中心化社交平台&#xff0c;功能众多&#xff0c;其中加密聊天功能为用户提供了安全的沟通方式。该功能利用了Signal加密协议&#xff0c;这是一种在Signal、WhatsApp和Skype等应用中广受欢迎的开源软件协议。 ComingChat在Sui上提供了全面的…