Android开发-应用广播

一、广播的核心概念

1. 什么是广播?

  • 广播(Broadcast):一条携带特定动作(Action)的 Intent 消息。
  • 发送者(Sender):通过 sendBroadcast()sendOrderedBroadcast() 等方法发送广播。
  • 接收者(Receiver):继承 BroadcastReceiver 的组件,用于接收并处理广播。

2. 广播的类型

类型描述示例
标准广播(Normal Broadcast)异步、无序发送,所有接收者几乎同时收到sendBroadcast()
有序广播(Ordered Broadcast)同步、按优先级顺序发送,可被拦截sendOrderedBroadcast()
粘性广播(Sticky Broadcast)广播发送后会“粘住”,新注册的接收者可立即收到sendStickyBroadcast()(已废弃)
本地广播(Local Broadcast)仅在应用内部发送和接收,更安全高效LocalBroadcastManager(已废弃)

二、广播接收者(BroadcastReceiver)

1. 定义 BroadcastReceiver

public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        
        switch (action) {
            case Intent.ACTION_BOOT_COMPLETED:
                Log.d("MyReceiver", "设备开机完成!");
                // 可在此启动后台服务(需用户授权)
                break;
                
            case Intent.ACTION_BATTERY_LOW:
                Log.d("MyReceiver", "电池电量低!");
                Toast.makeText(context, "电量不足,请及时充电", Toast.LENGTH_LONG).show();
                break;
                
            case "com.example.CUSTOM_ACTION":
                String data = intent.getStringExtra("data");
                Log.d("MyReceiver", "收到自定义广播:" + data);
                break;
        }
    }
}

⚠️ 注意onReceive() 方法在主线程执行,不能进行耗时操作(如网络请求、数据库读写)。如需后台任务,应启动 Service

三、注册广播接收者

方式 1:静态注册(清单文件注册)

AndroidManifest.xml 中声明,即使应用未运行也能接收广播。

<receiver android:name=".MyReceiver" android:enabled="true" android:exported="false">
    <intent-filter android:priority="1000">
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.intent.action.BATTERY_LOW" />
        <!-- 自定义广播 -->
        <action android:name="com.example.CUSTOM_ACTION" />
    </intent-filter>
</receiver>
🔐 权限说明
<!-- 接收开机广播需要权限 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<!-- 接收网络状态变化 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

优点:应用未启动也能接收系统广播。
缺点:可能被滥用,影响系统性能。

方式 2:动态注册(代码注册)

ActivityService 中注册,生命周期与组件绑定。

public class MainActivity extends AppCompatActivity {
    private MyReceiver receiver;
    private IntentFilter filter;

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

        // 创建过滤器
        filter = new IntentFilter();
        filter.addAction(Intent.ACTION_BATTERY_LOW);
        filter.addAction("com.example.CUSTOM_ACTION");

        // 创建接收者
        receiver = new MyReceiver();

        // 注册
        registerReceiver(receiver, filter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 必须反注册,防止内存泄漏!
        if (receiver != null) {
            unregisterReceiver(receiver);
        }
    }

    // 发送自定义广播
    public void sendCustomBroadcast(View view) {
        Intent intent = new Intent("com.example.CUSTOM_ACTION");
        intent.putExtra("data", "Hello from Activity!");
        sendBroadcast(intent);
    }
}

优点:灵活,可动态控制生命周期。
缺点:组件销毁后无法接收广播。

四、系统广播 vs 自定义广播

1. 常见系统广播

广播 Action说明权限
ACTION_BOOT_COMPLETED开机完成RECEIVE_BOOT_COMPLETED
ACTION_BATTERY_LOW电池电量低
ACTION_POWER_CONNECTED充电连接
ACTION_TIMEZONE_CHANGED时区变更
CONNECTIVITY_ACTION网络连接状态变化ACCESS_NETWORK_STATE
ACTION_SHUTDOWN设备关机SHUTDOWN

📢 注意:部分系统广播(如 BOOT_COMPLETED)在 Android 8.0+ 受到限制,应用必须在前台运行或用户明确授权才能接收。

2. 自定义广播

应用内部或跨应用通信。

// 发送
Intent intent = new Intent("com.yourcompany.YOUR_ACTION");
intent.putExtra("message", "Data from sender");
sendBroadcast(intent);

// 接收(需在清单或代码中注册该 action)

🔐 安全建议

  • 使用应用专属权限防止第三方应用接收。
  • 避免在广播中传递敏感信息。

五、Android 8.0+ 的广播限制

Android 8.0(API 26) 开始,Google 为了优化电池续航和系统性能,对隐式广播(Implicit Broadcasts)进行了严格限制。

1. 主要限制

  • ❌ 禁止在清单中静态注册大部分隐式广播(即非应用专属的 action)。
  • ✅ 仅允许在代码中动态注册
  • ✅ 少数例外(如 BOOT_COMPLETEDTIMEZONE_CHANGED)仍可在清单注册。

2. 如何适配?

  • 将原本静态注册的广播改为动态注册,并在合适的生命周期(如 onStart() / onStop())中注册/反注册。
  • 考虑使用 JobScheduler 或 WorkManager 替代长时间运行的广播任务。

六、现代替代方案

由于广播的限制和性能开销,Google 推荐使用更高效的通信方式:

1. 本地事件总线(推荐)

使用 LiveDataFlow 实现组件间通信。

// 使用 ViewModel + LiveData
public class SharedViewModel extends ViewModel {
    private MutableLiveData<String> message = new MutableLiveData<>();

    public LiveData<String> getMessage() { return message; }

    public void sendMessage(String msg) {
        message.setValue(msg);
    }
}

2. WorkManager

对于需要在特定条件下执行的后台任务(如网络可用时上传数据),使用 WorkManager

OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(UploadWorker.class)
    .setConstraints(new Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .build())
    .build();

WorkManager.getInstance(context).enqueue(work);

3. PendingIntent + AlarmManager

对于定时任务,使用 AlarmManager 设置 PendingIntent

七、最佳实践与避坑指南

  1. 务必在 onDestroy() 或 onStop() 中反注册动态广播,防止内存泄漏。
  2. 避免在 onReceive() 中执行耗时操作,应启动 Service 或使用 WorkManager
  3. 优先使用显式广播(指定包名)或应用内通信。
  4. 为自定义广播添加权限,提高安全性。
  5. Android 12+:部分广播(如 PACKAGE_ADDED)需要特殊权限或用户授权。

八、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值