android 之广播机制

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android 之广播机制相关的知识,希望对你有一定的参考价值。

参考技术A android 中的广播主要可以分为两种类型:标准广播和有序广播

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

标准广播工作示意图:

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

有序广播工作示意图:

可以让程序在未启动的情况下接收广播

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

在 AndroidManifest.xml 文件中注册

在 AndroidManifest.xml 文件中进行权限声明

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

先定义一个BroadcastReceiver来准备接收此广播

在 AndroidManifest.xml 文件中注册

有序广播是一种同步执行的广播,并且是可以被截断的。为了验证这一点,我们需要再创建一个新的BroadcastReceiver。新建AnotherBroadcastReceiver

同样,在 AndroidManifest.xml 文件中注册,同时,使用 intent-filter 标签的 android:priority 属性设置优先级

前面的 AnotherBroadcastReceiver 的优先级比较高,因此 AnotherBroadcastReceiver 一定比 MyBroadcastReceiver 先收到广播,因此,可以在 AnotherBroadcastReceiver 的 onReceive 方法中使用 abortBroadcast() 方法截断广播,这样 MyBroadcastReceiver 就收不到该广播了

在界面上弹出一个对话框,让用户无法进行任何其他操作,必须点击对话框中的“确定”按钮,关闭所有的Activity,然后回到登录界面即可

ActivityCollector 类用于管理所有的Activity,具有关闭所有Activity的功能

创建 BaseActivity 类作为所有 Activity 的父类,并在里面实现强制下线功能,在这里实现此功能,有以下几点原因

创建一个LoginActivity来作为登录界面

activity_login.xml

LoginActivity 如果输入 123 就到 MainActivity界面

MainActivity 中点击强制下线按钮,就发送强制下线的广播

MainActivity 布局

广播机制之动态注册和静态注册

文章目录

广播机制

广播机制简介

  • 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()方法运行时间比较长还没有结束的话,程序就会出现错误.

以上是关于android 之广播机制的主要内容,如果未能解决你的问题,请参考以下文章

Android连载19-广播机制之网络状态显示

广播机制之动态注册和静态注册

Android开发之广播

22 AndroidBroadcast广播机制

Android广播机制

Android广播机制