Android 零基础到精通之广播机制

目录
  • 广播机制简介
  • 接收系统广播
    • 1. 动态注册监听时间变化
    • 2. 静态注册实现开机启动
  • 发送自定义广播
    • 1. 发送标准广播
    • 2. 发送有序广播

广播机制简介

Android 中的广播主要分为两种类型:

  • 标准广播:一种异步执行的广播,广播发出后,所有的 BroadcasterReceiver 几乎会在同一时刻受到这条广播消息,没有任何时间顺序
  • 有序广播:一种同步执行的广播,广播发出后,同一时刻只有一个 BroadcasterReceiver 能够接受这条广播消息,当该 BroadcasterReceiver 中的逻辑执行完毕后,广播才会继续传递

接收系统广播

Android 内置了很多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到各种系统的状态信息

1. 动态注册监听时间变化

新建一个类,继承自 BroadcasterReceiver,并重写父类的 onReceive() 方法,这样当有广播来时,onReceive() 方法就会得到执行

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)
    }

    inner class TimeChangeReceiver : BroadcastReceiver() {

        override fun onReceive(context: Context?, intent: Intent?) {
            Toast.makeText(context, "Time has changed", Toast.LENGTH_SHORT).show()
        }
    }
}
  • 定义了一个内部类 TimeChangeReceiver,继承自 BroadcasterReceiver 并重写父类的方法,这样每当系统时间发生变化时,就会使用 Toast 提示一段文本信息
  • 在 onCreate() 方法创建一个 IntentFilter 实例,添加值为 android.intent.action.TIME_TICK 的 action,这也是系统时间发生变化时,系统会发出的广播的值
  • 创建 TimeChangeReceiver 实例,然后调用 registerReceiver() 方法进行注册,将 IntentFilter 实例和 TimeChangeReceiver 实例传进去,完成监听功能

2. 静态注册实现开机启动

动态注册的 BroadcasterReceiver 相对灵活,但必须在程序启动后才能接收广播,要想让程序在未启动的情况下也能接收广播,就需要使用静态注册的方式

创建类 BootCompleteReceiver,Exported 属性表示是否允许这个 BroadcasterReceiver 接收本程序以外的广播,Enabled 属性表示是否启用这个 BroadcasterReceiver,勾选这两个属性,点击 Finish 完成创建

class BootCompleteReceiver : BroadcastReceiver() {

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

静态的 BroadcasterReceiver 要在 AndroidManifest.xml 文件中注册才可以使用。由于 Android 系统启动完成后会发出一条值为 android.intent.action.BOOT_COMPLETED 的广播,所以我们在 <receiver> 标签中添加一个 <intent-filter> 标签,并在里面声明相应的 action。另外,还必须在 AndroidManifest.xml 中进行权限声明。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.fragmenttest">

    <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/Theme.FragmentTest">

        ...

        <receiver
            android:name="com.example.broadcasttest.BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

发送自定义广播

1. 发送标准广播

新建一个 MyBroadcasterReceiver,并在 onReceive() 方法中加入如下代码:

class MyBroadcasterReceiver : BroadcastReceiver() {

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

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

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.fragmenttest">

	...

    <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/Theme.FragmentTest">

        ...

        <receiver
            android:name="com.example.broadcasttest.MyBroadcasterReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcasttest.MyBroadcasterReceiver" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

接下来修改 activity_main.xml,定义一个按钮,作为发送广播的触发点

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send Broadcast" />

</LinearLayout>

修改 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.MyBroadcasterReceiver")
            intent.setPackage(packageName)
            sendBroadcast(intent)
        }
    }
}

这里对 setPackage() 方法做个说明,静态注册的 BroadcasterReceiver 是无法接收隐式广播的,而默认情况下我们发出的自定义广播都是隐式广播,因此这里要调用 setPackage() 方法,指定这条广播是发送给哪个应用程序的,从而让它变成一条显式广播

2. 发送有序广播

有序广播是一种同步执行的广播,并且可以被截断,我们再新建 AnotherBroadcasterReceiver

class AnotherBroadcasterReceiver : BroadcastReceiver() {

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

然后在 AndroidManifest.xml 中进行修改

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.fragmenttest">

   ...

    <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/Theme.FragmentTest">

		...

        <receiver
            android:name="com.example.broadcasttest.AnotherBroadcasterReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcasttest.MyBroadcasterReceiver" />
            </intent-filter>
        </receiver>

		...

    </application>

</manifest>

到目前为止,程序发出的都是标准广播,要发送有序广播,就要重新回到 BroadcasterTest 项目,然后修改 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.MyBroadcasterReceiver")
            intent.setPackage(packageName)
            sendOrderedBroadcast(intent, null)
        }
        ...
    }
}

sendOrderedBroadcast() 方法接收两个参数:第一个参数仍然是 Intent;第二个参数是一个与权限相关的字符串,这里传入 null 即可

接下来设定 BroadcasterReceiver 的先后顺序,修改 AndroidManifest.xml 中的代码

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.fragmenttest">

    ...

    <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/Theme.FragmentTest">
        <receiver
            android:name="com.example.broadcasttest.MyBroadcasterReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:priority="100">
                <action android:name="com.example.broadcasttest.MyBroadcasterReceiver" />
            </intent-filter>
        </receiver>

        ...

    </application>

</manifest>

通过 android:priority 属性给 BroadcasterReceiver 设置优先级,优先级比较高的 BroadcasterReceiver 就可以先收到广播。既然 MyBroadcasterReceiver 获得了接收广播的优先级,那么 MyBroadcasterReceiver 就可以选择是否允许广播继续传递了

class MyBroadcasterReceiver : BroadcastReceiver() {

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

在 onReceive() 方法中调用 abortBroadcaster() 方法,就表示将这条广播截断,后面的 BroadcasterReceiver 将无法再接收这条广播

到此这篇关于Android 零基础到精通之广播机制的文章就介绍到这了,更多相关Android 广播机制内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android BroadcastReceiver广播机制概述

    Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器).广播作为Android组件间的通信方式,可以使用的场景如下: 1.同一app内部的同一组件内的消息通信(单个或多个线程之间): 2.同一app内部的不同组件之间的消息通信(单个进程):  3.同一app具有多个进程的不同组件之间的消息通信:  4.不同app之间的组件之间消息通信:  5.Android系统在特定情况下与App之间的消

  • Android开发之广播机制浅析

    对于了解Android程序设计的人都知道,广播是Android开发中的一个重要的功能,在Android里面有各式各样的广播,比如:电池的状态变化.信号的强弱状态.电话的接听和短信的接收等等,今天本文就来给大家简单介绍一下系统发送.监听这些广播的机制. Android中的广播机制基本如下图所示: 那广播在Android程序中到底是如何运行的呢?下面将以代码的形式给大家好好分析一下: 一.发送广播 Intent是Activity中发送广播的桥梁,通过他我们可以轻松的将广播发送到系统中,具体的实现如下

  • Android 零基础到精通之广播机制

    目录 广播机制简介 接收系统广播 1. 动态注册监听时间变化 2. 静态注册实现开机启动 发送自定义广播 1. 发送标准广播 2. 发送有序广播 广播机制简介 Android 中的广播主要分为两种类型: 标准广播:一种异步执行的广播,广播发出后,所有的 BroadcasterReceiver 几乎会在同一时刻受到这条广播消息,没有任何时间顺序 有序广播:一种同步执行的广播,广播发出后,同一时刻只有一个 BroadcasterReceiver 能够接受这条广播消息,当该 BroadcasterRe

  • SpringBoot2零基础到精通之数据与页面响应

    目录 1 数据响应 1.1 数据响应(JSON为例) 1.2 数据响应之内容协商 2 页面响应 2.1 模板引擎之Thymeleaf 2.2 拦截器 2.3 文件上传 1 数据响应   数据响应一般分为两种:页面响应和数据响应,一般来说页面响应是用来开发一些单体项目(也就是前后端都在一个开发工具中),而数据响应则是用来进行前后端分离开发的项目,前端发送过来请求后端响应相应的数据. 1.1 数据响应(JSON为例)   如果想让SpringMVC响应返回一个JSON类型的数据,首先需要在项目的po

  • SpringBoot2零基础到精通之数据库专项精讲

    目录 1 数据库连接 1.1 配置数据库连接信息 1.2 整合Druid数据源 2 SpringBoot整合MyBatis 2.1 配置文件开发 2.2 纯注解开发 3 SpringBoot整合MyBatis-Plus 3.1 普通的CRUD方法 3.2 MyBatis-plus的分页实现 1 数据库连接 1.1 配置数据库连接信息   如果想要使用数据库连接池连接数据库进行SQL操作的话,在SpringBoot中需要经过如下三个步骤: 第一步: 导入jdbc开发的启动场景 <dependenc

  • SpringBoot2零基础到精通之异常处理与web原生组件注入

    目录 1 异常处理 1.1 异常处理之错误页面 1.2 异常处理之精确捕获 1.3 异常处理之自定义异常 1.4 异常处理之框架底层异常 2 web原生组件的注入 2.1 servlet组件 2.2 filter组件 2.3 listener组件 3 web实现定制化总结 1 异常处理   默认情况下,SpringBoot会提供/error处理所有的错误请求并返回相应的信息,对于浏览器客户端来说会返回一个包含时间戳.状态码.错误信息.携带的自定义异常信息.发生错误的路径等信息的错误Whitela

  • SpringBoot2零基础到精通之profile功能与自定义starter

    目录 1 profile功能 1.1 profile的生效规则 1.2 外部配置源 2 自定义starter 1 profile功能 1.1 profile的生效规则 为了方便多环境适配,SpringBoot简化了profile功能,具体的使用规则如下: ①在resources文件夹下可以一次创建多个application-xxx.yaml配置文件,分别对应着不同的生产.测试等环境,但是只有命名为application.yaml(或者后缀.properties的文件)文件会默认加载,所以说其他环

  • SpringBoot2零基础到精通之JUnit 5与指标监控

    目录 1 单元测试JUnit 5 1.1JUnit 5简介以及使用 1.2 常用的测试注解 1.3 断言(assertions) 1.4 前置条件(assumptions) 1.5 嵌套测试 1.6 参数化测试 2 指标监控 2.1 使用url实现监控 2.2 可视化的监控平台 1 单元测试JUnit 5 1.1JUnit 5简介以及使用   JUnit5作为最新版本的JUnit框架与之前版本的Junit框架有很大的不同.JUnit5主要由三个不同子项目的几个不同模块组成:JUnit Platf

  • SpringBoot2零基础到精通之自动配置底层分析及小技巧

    目录 1 自动配置底层分析 1.1 ​自动配置注解解析 1.2 修改默认配置 1.3 总结 1.4 最佳实践 2 开发小技巧 2.1 Lombok简化开发 2.2 伪热更新 2.3 创建Spring Initailizr项目 1 自动配置底层分析 1.1 ​自动配置注解解析 @SpringBootApplication注解是SpringBoot的核心注解,他是由以下三个注解总和而成. @SpringBootConfiguration 该注解底层有一个@Configuration注解,标明当前类是

  • SpringBoot2零基础到精通之配置文件与web开发

    目录 1 配置文件 1.1 yaml文件 1.1.1 基本语法 1.1.2 数据格式 1.2 数据绑定时关键字提示 2 web开发 2.1 静态资源的存放与访问 2.2 webjars 2.3 web小技巧 2.3.1 index页面 2.3.2 网页小图标 2.4 web场景源码浅析 1 配置文件   之前说过,配置文件大致分两种类型:properties.yaml.其中properties是最常规的配置文件类型:使用键值对等号的格式来对各种参数进行配置,后缀为.properties,在这里就

  • SpringBoot2零基础到精通之映射与常用注解请求处理

    目录 1 请求映射 1.1 Rest风格 1.2 表单提交Rest的原理 1.3请求映射的原理 2 请求处理常用注解 2.1 @RequestParam 2.2 @PathVariable 2.3 @RequestHeader 2.4 @RequestBody 2.5 @RequestAttribute 2.6 @RequestAttribute 3 方法参数小技巧 3.1 复杂参数属性值 3.2 自定义参数实现数据绑定 1 请求映射   在SpringBoot中使用@XxxMapping注解完

随机推荐