13、广播接收器与服务:BroadcastReceiver静态与动态注册、自定义广播、Service生命周期与启动方式、IntentService与WorkManager

广播接收器和服务,这两个东西在Android里就像一对老搭档。一个负责“喊话”,一个负责“干活”。我刚开始学的时候,总觉得它们有点抽象,尤其是广播,感觉像在玩对讲机。但用多了你会发现,它们其实是解耦和后台任务的利器。

13.1 广播接收器:两种注册方式

广播接收器,说白了就是监听系统或应用发出的“消息”。比如电量低了、网络变了、屏幕亮了,系统都会“喊一嗓子”。你的接收器如果注册了对应的“频道”,就能听到并做出反应。

注册方式有两种:静态注册和动态注册。嗯,这里有个坑,我当年踩过。

13.1.1 静态注册

静态注册是在 AndroidManifest.xml 里声明的。应用安装时,系统就记住了这个接收器。哪怕应用没在运行,广播来了也能唤醒它。

举个例子,监听开机完成广播:

<receiver android:name=".BootReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

对应的Java代码:

public class BootReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // 开机后,你想干点啥?
        Toast.makeText(context, "手机开机了!", Toast.LENGTH_SHORT).show();
    }
}
注意:从Android 8.0开始,大部分隐式广播(非应用内)已经不支持静态注册了。系统为了省电和隐私,砍掉了这个“后门”。我曾经维护过一个老项目,升级targetSdk后,开机广播死活不触发,查了半天才发现是静态注册失效了。

13.1.2 动态注册

动态注册是在代码里用 registerReceiver() 完成的。它的生命周期跟着组件走,Activity或Service销毁了,记得要 unregisterReceiver(),否则会内存泄漏。

我习惯在 onResume() 里注册,onPause() 里注销。这样最安全。

// 注册
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_LOW);
registerReceiver(batteryReceiver, filter);

// 注销(别忘了!)
@Override
protected void onPause() {
    super.onPause();
    unregisterReceiver(batteryReceiver);
}
小技巧:动态注册的接收器,优先级比静态注册高。而且你可以控制它什么时候“听”,什么时候“不听”,灵活很多。

13.2 自定义广播:自己发消息

除了听系统的,你也可以自己发广播。这在组件间通信时特别好用。比如A页面做了个操作,想让B页面知道,但又不想用EventBus这种第三方库。

发送自定义广播:

Intent intent = new Intent("com.example.MY_CUSTOM_ACTION");
intent.putExtra("data", "你好,广播!");
sendBroadcast(intent);

接收端注册:

IntentFilter filter = new IntentFilter("com.example.MY_CUSTOM_ACTION");
registerReceiver(myReceiver, filter);

个人经验:自定义广播的action字符串,最好加上包名前缀,比如 com.example.app.MY_ACTION。否则容易跟其他应用的广播冲突。我见过一个项目,两个第三方SDK用了同一个action名字,结果广播互相干扰,调试了一整天。

13.3 Service:后台的“长工”

Service是Android里做后台任务的组件。它没有界面,默默在后台运行。你想想看,下载文件、播放音乐、上传日志,这些活儿都适合交给Service。

13.3.1 生命周期

Service的生命周期比Activity简单多了。主要就这几个回调:

  • onCreate():创建时调用,只调用一次。
  • onStartCommand():每次 startService() 都会调用。
  • onBind():绑定服务时调用。
  • onDestroy():销毁时调用。

我画了个图,帮你理清关系:

Service 生命周期 startService() onCreate() onStartCommand() onDestroy() 多次 startService

13.3.2 启动方式

Service有两种启动方式,说白了就是“两种用法”:

启动方式 方法 特点 适用场景
启动式 startService() 独立运行,不依赖调用者。调用者退出,Service还在跑。 下载、播放音乐
绑定式 bindService() 与调用者绑定,调用者销毁,Service跟着销毁。 需要交互、获取数据

我个人习惯:如果只是后台默默干活,用 startService()。如果需要跟Service通信(比如获取下载进度),就用 bindService()。也可以两者结合,先启动再绑定。

13.4 IntentService:自动停的“好帮手”

普通Service有个麻烦:它运行在主线程。如果你在里面做耗时操作,必须自己开子线程。而且做完后,还得手动 stopSelf() 停止。否则Service会一直挂着。

IntentService就是来解决这个痛点的。它内部自带工作线程,任务执行完自动停止。说白了,就是“即用即走”。

public class MyIntentService extends IntentService {
    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        // 这里已经在子线程了,放心做耗时操作
        String action = intent.getStringExtra("action");
        Log.d("TAG", "处理任务: " + action);
    }
}

避坑指南:IntentService在Android 8.0之后被标记为废弃了。虽然还能用,但官方推荐用 JobIntentServiceWorkManager。我建议新项目直接上WorkManager,别再用老古董了。

13.5 WorkManager:现代后台任务方案

WorkManager是Google推荐的现代后台任务库。它最大的优点是:保证任务执行。哪怕应用被杀、手机重启,任务也会在条件满足时重新执行。

你想想看,以前用Service做后台上传,用户一划杀应用,任务就丢了。WorkManager不会,它会记住任务,等下次开机或网络恢复时继续执行。

基本用法:

// 定义任务
OneTimeWorkRequest uploadWork = new OneTimeWorkRequest.Builder(UploadWorker.class)
        .setConstraints(new Constraints.Builder()
                .setRequiredNetworkType(NetworkType.CONNECTED) // 需要网络
                .build())
        .build();

// 提交任务
WorkManager.getInstance(context).enqueue(uploadWork);

Worker类:

public class UploadWorker extends Worker {
    public UploadWorker(Context context, WorkerParameters params) {
        super(context, params);
    }

    @NonNull
    @Override
    public Result doWork() {
        // 在这里做上传操作
        return Result.success(); // 返回成功
    }
}
个人建议:如果你的任务需要“保证完成”,比如上传日志、同步数据,直接用WorkManager。如果是即时性的后台操作,比如播放音乐,还是用前台Service。WorkManager不适合做需要持续运行的任务。

13.6 总结对比

最后,我整理了一个对比表,方便你选型:

组件 适用场景 生命周期 推荐指数
BroadcastReceiver 监听系统广播、组件间通信 短,onReceive执行完就结束 ⭐⭐⭐⭐
Service 后台持续运行(音乐、定位) 长,需手动停止 ⭐⭐⭐
IntentService 一次性后台任务(已废弃) 自动停止
WorkManager 可延迟、需保证完成的后台任务 由系统调度 ⭐⭐⭐⭐⭐

嗯,广播和服务这块内容不少,但核心就这几个点。你只要记住:广播是“喊话”,Service是“干活”,WorkManager是“靠谱的管家”。项目中多练几次,自然就熟了。


公众号:蓝海资料掘金营,微信deep3321