Android四大组件——Broadcast

一、什么是Broadcast

在安卓系统中,广播是一种通信机制,用于在各种组件之间传递消息。广播允许应用程序的不同部分或不同应用程序之间进行通信。广播主要用于通知其它组件特定事件的发生。例如设备启动、网络连接状态更改、电池电量变化等。

二、广播概述

广播在日常生活中较为常见。例如每个教室均有一个音响,当上课/下课时,该音响就会接收到一个广播信号,开始广播上课/下课铃。

与之类似,安卓中的广播用于从广播发送者向各个广播接收者发送消息,是安卓四大组件之一。安卓广播是实现跨程序或程序内部通信的重要机制。广播允许应用程序的不同部分或不同应用程序之间发送和接收消息,以便在特定事件发生时进行响应或执行相应的操作。因此,通过广播可以实现安卓的线程/进程间通信。

广播组件主要由两个角色组成:

1.广播发送者(Broadcast Sender):负责发送广播消息。发送者可以是应用程序的任何组件,如活动(Activity)、服务(Service)。

2.广播接收者(Broadcast Receiver):负责接收广播消息并对其进行响应。接收者需要注册到系统中以便在特定事件发生时接收广播。

广播接收者订阅感兴趣的广播(通知)。当广播发送者发出相应的广播(通知)时,所订阅的接收者就会收到相应的数据,并进行业务处理。具体来说,其实现方式如下:

1)广播接收者通过Binder在Activity Manager Service(AMS)中注册(订阅感兴趣的广播)

2)广播发送者通过Binder向AMS发送广播

3)AMS通过(Intent Filter/Permission)查找注册(订阅)该广播的接收者,并把消息送入消息队列

4)消息抵达接收者,触发接收者的on Receive回调。可以在该回调中对获取的广播数据进行处理

广播组件的使用场景广泛,包括但不限于:

单个APP的单个组件(单个或多个线程)

单个APP多个组件(单进程)

单个APP不同进程的组件(多进程)

多个APP之间通信

安卓系统与某个APP进行通信

可见,广播机制非常适用于不同进程之间的通信

三、广播接收者

1.广播接收者的创建

(1)通过Android Studio中的New -> Other -> Broadcast Receiver来创建 在对应的包右击(例如默认的Main Activity所在的包),依次如下创建。

on Receive用于接收广播消息。可见,广播消息依然是一种Intent

通过这种方法创建的广播接收者,会被自动注册到配置文件中

(2)也可以手动实现广播接收者 简单来说,其步骤如下:

a.创建一个类,继承Broadcast Receiver 

b.实现其中的on Receiver回调

2.注册(订阅)广播事件

(1)静态注册(安卓8.0后对该方法进行了限制,不推荐)

(2)动态注册

3.静态注册

静态注册方法涉及 intent-filter。隐式 Intent 不直接指定目标组件的类名,而是通过指定动作(Action)、数据类型(Data)和/或类别(Category)来描述要执行的操作,系统会根据这些信息选择合适的组件来响应 Intent。

因此,静态注册方法也是在配置文件中,通过intent-filter为广播接收器注册所要接收的事件。例如,接收时区变化的系统广播

首先在配置文件中为该接收器进行静态注册

然后在对应类的onReceive方法中处理接收到该广播后的逻辑

之后修改手机的时区。默认时区是中国时区,这里随便修改成别的时区,观察logcat的结果

广播接收者的静态注册较为简单,且应用退出后依然可以接受到广播消息。因此,考虑到权限安全以及电池功耗等问题,安卓8.0后的版本无法通过静态注册接收大部分系统广播。

4.动态注册

现在大部分的广播接收者采用动态注册的方式。下面以电池电量变化广播为例。 首先,无论是静态注册还是动态注册

首先需要创建一个广播接收器类

ReceiverDemo02.kt

package com.example.review04

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.BatteryManager

class ReceiverDemo02 : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        // This method is called when the BroadcastReceiver is receiving an Intent broadcast.
        TODO("ReceiverDemo02.onReceive() is not implemented")
        val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL,-1)
        println("当前电量:${level}")
    }
}

接下来,在一个Activity的on Create回调中动态地为该接收器注册电量变化广播

Demo01Activity.kt

package com.example.review04

import android.content.Intent
import android.content.IntentFilter
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.PersistableBundle

class Demo01Activity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_demo01)
    }

    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
        super.onCreate(savedInstanceState, persistentState)
        val intentFilter = IntentFilter()
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED)
        val batteryReceiver = ReceiverDemo02()
        registerReceiver(batteryReceiver,intentFilter)
    }
}

修改安卓设备的电量,模拟器中可通过图示方法。观察logcat的输出

我们实现了一个简单的动态注册的广播接收器。但是当Activity在后台运行时,该接收器依然会接收广播,且无法关闭。一个更加合理的动态注册代码如下:

Demo02Activity.kt

package com.example.review04

import android.content.Intent
import android.content.IntentFilter
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class Demo02Activity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_demo02)
    }

    private lateinit var batteryReceiverDemo02: ReceiverDemo02

    override fun onResume() {
        super.onResume()
        val intentFilter = IntentFilter()
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED)
        batteryReceiverDemo02 = ReceiverDemo02()
        registerReceiver(batteryReceiverDemo02,intentFilter)
    }

    override fun onPause() {
        super.onPause()
        unregisterReceiver(batteryReceiverDemo02)
    }
}

对比动态注册与静态注册:

四、自定义广播

广播接收者接收时区变化和电量变化的广播,这些都是系统发出的广播。当然也可以自行编写代码,发送自定义广播,实现更加复杂的功能。 

实现自定义广播较为简单,只需要通过sendBroadcast方法发送广播即可

举例:点击按钮,发送自定义广播,并接收该广播,打印消息

activity_demo03.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Demo03Activity">

    <Button
        android:id="@+id/btn_BC"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="发送"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        tools:ignore="MissingConstraints" />

  </androidx.constraintlayout.widget.ConstraintLayout>

Demo03Activity.kt

package com.example.review04

import android.content.Intent
import android.content.IntentFilter
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button

class Demo03Activity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_demo03)

        val btnBC = findViewById<Button>(R.id.btn_BC)
        btnBC.setOnClickListener {
            val intent = Intent()
            intent.action = "CUSTOM_BROADCAST"
            sendBroadcast(intent)
        }
    }

    override fun onResume() {
        super.onResume()
        val intentFilter = IntentFilter()
        intentFilter.addAction("CUSTOM_BROADCAST")
        val customReceiverDemo03 = ReceiverDemo03()
        registerReceiver(customReceiverDemo03,intentFilter)
    }
}

ReceiverDemo03.kt

package com.example.review04

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent

class ReceiverDemo03 : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        println("接收到自定义广播")
        println(intent.action)
    }
}

运行后查看:

自定义广播的用途主要包括以下几个方面:

1. 组件间通信 自定义广播允许应用内的不同组件(如Activity、Service、Fragment)进行通信。例如Service可以发送广播通知Activity某个任务已完成,Activity接收到广播后更新UI。

2. 解耦 通过广播机制,可以使发送者和接收者之间的耦合度降低。发送广播的组件不需要知道接收广播的具体组件,实现了松耦合设计,提高了代码的模块化和可维护性。

3. 跨进程通信 在某些情况下,自定义广播可以用于跨进程通信。例如,当应用分为多个进程运行时,可以通过自定义广播在不同进程之间传递消息。

五、广播的类型

安卓中的广播类型主要有如下两种:

标准广播(Normal Broadcasts)(无序广播):标准广播/无序广播是完全异步的。所有接收器几乎同时接收广播,无法控制广播接收的顺序。该广播使用sendBroadcast()方法发送。

有序广播(Ordered Broadcasts):有序广播是同步的,一个接一个地按顺序传递广播,接收器可以决定是否将广播传递给下一个接收器。接收器可以修改广播数据或者截断广播的传播。有序广播使用sendOrderedBroadcast()方法发送。

1.无序广播:使用sendBroadcast()方法发送即可。

2.有序广播:首先,编写两个广播接收者

为两个接收器分别注册广播事件:

发送有序广播:

sendOrderBroadcast中第二个参数用于指定哪些接收者可以接收该广播,一般设为null即可

运行结果:

考虑到难以确保程序以合适的顺序注册各个接收者。因此可以为各个接收者设置优先级,实现规定的顺序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值