【Android】四大组件之BroadcastReceiver

目录

一、什么是BroadcastReceiver

二、创建和使用BroadcastReceiver

三、跨应用广播接收权限

四、广播方式

五、广播类型与特性

六、BroadcasReceiver注册方式

七、BroadcasReceiver工作流程


你可以把广播接收器想象成一个"收音机"。它的作用是监听系统或应用发出的"广播消息",并在收到消息后执行相应的操作。

一、什么是BroadcastReceiver

BroadcastReceiver用于监听系统或应用发出的广播事件,实现跨组件通信。其特点是发送方无需关注接收方是否存在或如何处理数据

1. 广播的类型

  • **系统广播:**由系统发出,比如电池电量低、网络状态变化、屏幕开关等。

ACTION_BATTERY_LOW:电池电量低。

ACTION_BOOT_COMPLETED:设备启动完成。

  • **自定义广播:**由应用发出,用于应用内部或应用之间的通信。

在App中定义一个广播,比如"任务完成",然后在其他地方接收并处理。

2. 生命周期管理

广播接收器的生命周期非常短暂,它只存在于接收到广播并处理完广播的这段时间内。

  • 接收广播:当广播发出时,系统会创建广播接收器的实例,并调用它的onReceive()方法。
  • 完成任务:onReceive()方法执行完毕后,广播接收器的实例就会被销毁。

3. 典型场景

典型场景 实现方案
强制下线功能 发送全局广播通知所有界面退出登录,动态注册接收器处理跳转逻辑
多应用协同 通过自定义广播与权限控制,实现应用间数据传递与功能触发
系统事件响应 静态注册监听 SCREEN_ON/SCREEN_OFF 等系统广播,实现锁屏/亮屏逻辑

二、创建和使用BroadcastReceiver

1‌. 继承基类

新建类继承 BroadcastReceiver,并重写 onReceive() 方法:

java 复制代码
public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        // 处理广播逻辑,如弹出 Toast
        Toast.makeText(context, "收到广播", Toast.LENGTH_SHORT).show();
    }
}

onReceive() 方法执行时间需控制在 10 秒内,否则会触发 ANR 错误。

建议复杂逻辑通过 IntentServiceWorkManager 异步处理。

2. 注册广播接收器

广播接收器可以通过两种方式注册:

  • 动态注册(接收方代码中注册):需手动注册和注销,生命周期与注册的 Context(如 Activity)绑定,应用关闭后失效。
java 复制代码
// 注册
IntentFilter filter = new IntentFilter("CUSTOM_ACTION");
MyReceiver receiver = new MyReceiver();
registerReceiver(receiver, filter);

// 注销(如 onDestroy 中)
unregisterReceiver(receiver);

为避免内存泄漏,动态注册的接收器需在适当时机(如 onDestroy())注销 。

  • 静态注册(接收方AndroidManifest.xml):应用未启动时也能接收广播(如系统启动完成事件),但 Android 8.0+ 对隐式广播有限制。
XML 复制代码
// BroadcastReceiver使用者(接收方)的AndroidManifest.xml
// 允许应用监听设备启动完成的广播
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver android:name=".MyReceiver">
    <intent-filter>
        <action android:name="CUSTOM_ACTION" />
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

Android 8.0+ 限制‌:针对隐式广播(非定向广播),静态注册可能失效,需改用动态注册或使用豁免列表中的广播 。

3. 发送广播

  • 发送标准广播
java 复制代码
Intent intent = new Intent("CUSTOM_ACTION");
intent.putExtra("data", "Hello");
sendBroadcast(intent);
  • 发送有序广播:可设置优先级和拦截广播
java 复制代码
// 发送方代码:发送有序广播
Intent intent = new Intent("ORDERED_ACTION");
sendOrderedBroadcast(intent, null);

// 接收方配置:接收器中设置优先级(AndroidManifest.xml)
<intent-filter android:priority="100">
    <action android:name="ORDERED_ACTION" />
</intent-filter>

// 接收方代码:在 onReceive() 中拦截广播
abortBroadcast();

敏感广播需添加权限控制,防止恶意应用拦截。

三、跨应用广播接收权限

场景 发送方配置 接收方配置
sendBroadcast() 附加权限 定义 <permission>,无需声明权限 声明 <uses-permission>
<receiver> 设置权限 声明 <uses-permission> 定义 <permission><receiver> 中绑定
  1. 发送方通过 sendBroadcast() 附加权限

发送方需在自身 AndroidManifest.xml 中通过 <permission> 标签定义权限。

XML 复制代码
<permission 
    android:name="com.example.SEND_PERMISSION" 
    android:protectionLevel="signature" />  

发送广播时需指定此权限:

java 复制代码
sendBroadcast(intent, "com.example.SEND_PERMISSION");  

发送方无需通过 <uses-permission> 声明该权限,而‌接收方需在 Manifest 中声明该权限‌,否则无法接收广播:

XML 复制代码
<uses-permission android:name="com.example.SEND_PERMISSION" />

若权限的 protectionLevel 设为 signature,发送方与接收方需使用相同签名。

也就是说,发送方与接收方应用必须使用相同的数字证书(即开发者签名密钥)进行签名‌。

2. 接收方通过 <receiver> 标签的 android:permission 属性限制发送方权限

接收方需在 Manifest 中定义新权限‌(如 RECEIVE_PERMISSION),并在 <receiver> 标签中设置:

XML 复制代码
<permission android:name="com.example.RECEIVE_PERMISSION" />  
<receiver  
    android:name=".MyReceiver"  
    android:permission="com.example.RECEIVE_PERMISSION">  
    <intent-filter>...</intent-filter>  
</receiver>  

‌发送方需在自己的 Manifest 中声明该权限‌,否则发送的广播会被接收方拒绝:

XML 复制代码
<uses-permission android:name="com.example.RECEIVE_PERMISSION" />  

系统广播应用场景

  • 监听开机启动 ‌:静态注册 BOOT_COMPLETED 广播,需声明权限 RECEIVE_BOOT_COMPLETED
  • 监听网络变化 ‌:动态注册 CONNECTIVITY_CHANGE 广播,需权限 ACCESS_NETWORK_STATE

四、广播方式

特性 显式广播 隐式广播
目标范围 明确指定接收方组件或包名 通过 IntentFilter 匹配所有符合条件的接收方
注册限制 允许接收方静态注册(Android 8.0+ 无限制) 禁止接收方静态注册(Android 8.0+ 限制)
通信范围 适用于定向通信(如应用内部或特定合作应用) 适用于广播全局事件(如系统事件通知)
安全性 更高(需明确目标权限或签名验证) 较低(可能被恶意应用劫持)

1. 显示广播

  • 指定报包名
java 复制代码
Intent intent = new Intent("CUSTOM_ACTION");  
intent.setPackage("com.example.receiverapp"); // 限定接收方包名  
sendBroadcast(intent);  
  • 指定组件类名
java 复制代码
Intent intent = new Intent("CUSTOM_ACTION");  
intent.setComponent(
    new ComponentName("com.example.receiverapp", "com.example.ReceiverClass"));  
sendBroadcast(intent);  

显式广播通过精确指定接收方身份,绕过 Android 8.0+ 对隐式广播静态注册的限制,适用于需定向通信的场景。开发者应优先使用动态注册或显式广播,确保应用兼容性及安全性。

2. 隐式广播

发送方仅定义 Action,依赖接收方声明的 IntentFilter 匹配广播,适用于全局事件通知。

java 复制代码
Intent intent = new Intent("CUSTOM_ACTION");  
sendBroadcast(intent); // 不指定目标接收方  

隐式广播的发送方仅需在代码中定义 IntentAction 并发送,‌无需在 XML 文件中进行任何配置 ‌。接收方需自行处理 IntentFilter 的注册与适配规则。

五、广播类型与特性

1. 普通广播(标准广播)

所有接收器‌并行接收‌,无顺序限制,无法终止传播。

java 复制代码
sendBroadcast(new Intent("com.example.ACTION_STANDARD"));  

2. ‌有序广播(Ordered Broadcast)

接收器‌按优先级顺序处理‌,可中断传播或修改数据。

发送方式:

java 复制代码
sendOrderedBroadcast(intent, null);  

接收方注册:

XML 复制代码
<receiver android:name=".HighPriorityReceiver">  
    <intent-filter android:priority="1000">  
        <action android:name="com.example.ACTION_ORDERED" />  
    </intent-filter>  
</receiver>  

3. 本地广播(Local Broadcast)

仅在应用内部传递广播,避免跨应用风险(已弃用 LocalBroadcastManager,推荐 LiveDataRxJava 替代)。

本地广播发送方式:

java 复制代码
Intent localIntent = new Intent("com.example.ACTION_LOCAL");  
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);  

六、 BroadcasReceiver 注册方式

对比维度 静态注册 动态注册
注册方式 AndroidManifest.xml 中通过 <receiver> 标签声明 在代码中通过 registerReceiver() 动态注册,需手动管理生命周期
生命周期管理 独立于组件生命周期,系统自动创建和销毁(应用未运行也可接收广播) 与注册上下文(如 Activity/Service)生命周期绑定,需在 onDestroy() 中手动注销
注册时机 应用安装时完成,全局生效 运行时按需注册,作用域可控
广播类型适配 Android 8.0+ 受限:仅支持接收豁免的系统隐式广播 无条件支持所有广播类型(显式/隐式)
系统兼容性 需适配 Android 8.0+ 隐式广播限制 无版本限制,适配性更强
性能影响 长期占用系统资源(应用安装时即注册,增加系统负载) 按需注册和释放资源,内存占用更灵活
安全性 潜在风险:恶意应用可能监听隐式广播 可控性高:仅应用运行时生效,且可限制接收范围(如权限控制)
适用场景 需长期监听系统事件(如开机启动、网络变化) 临时监听应用内事件(如用户交互触发的自定义广播)
代码复杂度 配置简单,无需额外代码管理 需编写注册/注销代码,逻辑复杂度更高
内存泄漏风险 未及时注销会导致内存泄漏
资源占用 长期占用系统资源,可能影响性能 按需释放资源,优化内存使用

Android 8.0+ 隐式广播限制‌:

  • 静态注册仅支持部分系统广播(如 ACTION_BOOT_COMPLETED)。
  • 动态注册或显式广播(指定包名/组件名)是兼容高版本的推荐方案。

安全性建议‌:

  • 静态注册需谨慎使用,优先通过权限(android:permission)限制接收方。
  • 动态注册可通过 LocalBroadcastManager(已弃用)或 LiveData 替代高频广播场景。

长期系统监听用静态注册,临时或安全敏感场景用动态注册。

避免静态注册高频广播,动态注册按需启停更灵活。

1. 静态注册示例

接收方创建 BroadcastReceiver 子类

java 复制代码
public class MyStaticReceiver extends BroadcastReceiver {  
    @Override  
    public void onReceive(Context context, Intent intent) {  
        String action = intent.getAction();  
        if ("com.example.STATIC_ACTION".equals(action)) {  
            String data = intent.getStringExtra("data");  
            Toast.makeText(context, "静态接收器: " + data, Toast.LENGTH_SHORT).show();  
        }  
    }  
}  

接收方在 AndroidManifest.xml 中声明

XML 复制代码
// 允许应用监听设备启动完成的广播
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver  
    android:name=".MyStaticReceiver"  
    android:enabled="true"  
    android:exported="true">  
    <intent-filter>  
        <action android:name="com.example.STATIC_ACTION" />  
        <!-- 可添加系统广播 Action(如开机完成) -->  
        <action android:name="android.intent.action.BOOT_COMPLETED" />  
    </intent-filter>  
</receiver>  

发送方发送广播代码

java 复制代码
Intent intent = new Intent("com.example.STATIC_ACTION");  
intent.putExtra("data", "静态广播测试");  
sendBroadcast(intent);  

在 Android 3.1+ 系统中,应用需至少被用户手动启动一次;否则,即使声明权限,也无法接收开机广播。

部分厂商系统(如 MIUI、EMUI)可能默认禁止应用自启动,需用户手动开启。

2. 动态注册示例

接收方在 Activity 中注册与注销

XML 复制代码
public class MainActivity extends AppCompatActivity {  
    private BroadcastReceiver dynamicReceiver;  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  

        // 动态注册接收器  
        dynamicReceiver = new BroadcastReceiver() {  
            @Override  
            public void onReceive(Context context, Intent intent) {  
                String data = intent.getStringExtra("data");  
                Toast.makeText(context, "动态接收器: "
                    + data, Toast.LENGTH_SHORT).show();  
            }  
        };  

        IntentFilter filter = new IntentFilter("com.example.DYNAMIC_ACTION");  
        registerReceiver(dynamicReceiver, filter);  
    }  

    @Override  
    protected void onDestroy() {  
        super.onDestroy();  
        // 必须手动注销  
        unregisterReceiver(dynamicReceiver);  
    }  
}  

发送方发送广播

java 复制代码
Intent intent = new Intent("com.example.DYNAMIC_ACTION");  
intent.putExtra("data", "动态广播测试");  
sendBroadcast(intent);  

动态注册未及时调用 unregisterReceiver()会导致内存泄漏‌。

此外,在 onPause()onDestroy() 中要及时注销接收器。

七、BroadcasReceiver工作流程

BroadcastReceiver的核心抽象类是android.content.BroadcastReceiver

java 复制代码
public abstract class BroadcastReceiver {
    // 核心方法,用于接收广播
    public abstract void onReceive(Context context, Intent intent);
 
    // 其他方法,比如设置结果、获取结果等
    public final void setResultCode(int code) { ... }
    public final int getResultCode() { ... }
    public final void setResultData(String data) { ... }
    public final String getResultData() { ... }
    public final void setResultExtras(Bundle extras) { ... }
    public final Bundle getResultExtras(boolean makeMap) { ... }
}
  • 静态注册:由PackageManagerService解析AndroidManifest.xml并注册。
  • 动态注册:通过Context.registerReceiver()注册到ActivityManagerService。
  • 通过Context.sendBroadcast()发送广播,ActivityManagerService负责分发。
  • 分发广播:BroadcastQueue从队列中取出广播,并调用广播接收器的onReceive()方法处理。
  • 处理广播:广播接收器的onReceive()方法运行在主线程中,不能执行耗时操作。
  • 广播流程‌:事件触发 → 封装 Intent → 发送 → 接收处理 → 生命周期管理。

无论是静态还是动态注册,‌系统默认每次广播触发时都会创建新的BroadcastReceiver实例‌,并在 onReceive() 执行完毕后销毁 。

静态注册的接收器每次均由系统创建新实例,无法复用旧实例,因此不存在同一实例多次响应广播的情况。

动态注册时未及时调用 unregisterReceiver(),导致同一接收器实例被多次注册(如多次跳转同一 Activity 且未解注册),广播触发时系统会多次调用该实例的 onReceive()

java 复制代码
// Activity 中重复注册同一接收器  
@Override  
protected void onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);  
    IntentFilter filter = new IntentFilter("com.example.ACTION_TEST");  
    registerReceiver(receiver, filter);  // 每次 Activity 创建都会注册一次  
}  

适配建议‌:遵循生命周期管理原则,避免非预期的重复注册与逻辑执行。

相关推荐
xiangpanf9 小时前
Laravel 10.x重磅升级:五大核心特性解析
android
robotx12 小时前
安卓线程相关
android
消失的旧时光-194312 小时前
Android 面试高频:JSON 文件、大数据存储与断电安全(从原理到工程实践)
android·面试·json
dalancon13 小时前
VSYNC 信号流程分析 (Android 14)
android
dalancon13 小时前
VSYNC 信号完整流程2
android
dalancon13 小时前
SurfaceFlinger 上帧后 releaseBuffer 完整流程分析
android
用户693717500138414 小时前
不卷AI速度,我卷自己的从容——北京程序员手记
android·前端·人工智能
程序员Android15 小时前
Android 刷新一帧流程trace拆解
android
墨狂之逸才15 小时前
解决 Android/Gradle 编译报错:Comparison method violates its general contract!
android
阿明的小蝴蝶16 小时前
记一次Gradle环境的编译问题与解决
android·前端·gradle