PAYATHON 2026

如何在 BroadcastReceiver 创建的 Worker 中访问 Application 的仓库实例?

数据阿明

直接通过 applicationContext 访问

将 Worker 的 applicationContext 转换为自定义的 CheckInApplication,就可以访问它的 container 属性:

val application = applicationContext as CheckInApplication
val container = application.container

这要求应用已在 AndroidManifest.xml 中将 CheckInApplication 配置为 Application 类。BroadcastReceiver 负责触发任务,不影响 Worker 通过这种方式访问应用容器。

为什么需要类型转换?

applicationContext 的声明类型是 Context,编译器只能通过它访问 Context 定义的成员。container 是 CheckInApplication 声明的属性,因此需要先转换类型。

在正常的 Android 组件启动流程中,系统会先创建当前进程的 Application 并执行其 onCreate(),之后 Worker 才会执行。因此,Worker 可以使用原代码在 onCreate() 中初始化的容器。

在 Worker 中调用仓库方法

原始代码没有提供 AppContainer 的定义和仓库方法名。下面假设容器公开了 repository 属性,仓库提供 checkIn() 方法;请按项目中的实际名称替换:

import kotlinx.coroutines.CancellationException

class CheckInWorker(
    ctx: Context,
    params: WorkerParameters
) : CoroutineWorker(ctx, params) {

    private val tag = "CHECK_IN_WORKER"

    override suspend fun doWork(): Result {
        return try {
            val application = applicationContext as CheckInApplication
            val repository = application.container.repository

            repository.checkIn()

            Log.d(tag, "Work Success")
            Result.success()
        } catch (cancelled: CancellationException) {
            throw cancelled
        } catch (exception: Exception) {
            Log.e(tag, "Work failure", exception)
            Result.failure()
        }
    }
}

如果 repository 只在 DefaultAppContainer 中声明,而 AppContainer 没有公开该属性,就无法通过当前类型为 AppContainer 的 container 访问它。应在 AppContainer 的接口或基类中公开 Worker 所需的仓库属性。

代码单独重新抛出 CancellationException,以便协程取消正常传播,避免像原代码中的 catch (Throwable) 那样将取消也转换为工作失败。

检查 manifest 配置

在现有的 <application> 元素中设置 android:name:

<application
    android:name=".CheckInApplication">
    <!-- 保留现有的组件声明与其他配置 -->
</application>

如果类不在对应的应用基础包下,可以填写完整类名。配置不正确时,实际的 Application 实例可能不是 CheckInApplication,强制转换会抛出 ClassCastException。

注意实例的生命周期

这种方式访问的是当前进程中 Application 持有的容器。进程终止后,内存中的仓库实例不会保留;WorkManager 后续运行任务时,应用会重新创建 Application 和容器。

如果配置了多个进程,每个进程都有自己的 Application 实例,不能通过这种方式共享同一个内存对象。需要跨进程或跨进程重启保存的数据,应放在持久化存储中。

备注:内容仅供参考。