You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Dagger-Hilt的CoroutineWorker实例化失败(NoSuchMethodException)排查

问题:WorkManager无法实例化NotificationsWorker(NoSuchMethodException)

基于Jetpack Compose和Dagger-Hilt开发Android应用,需实现每日周期性通知功能,通知标题根据当前日期从Room数据库获取。但Worker执行任务时,Logcat抛出java.lang.NoSuchMethodException,无法实例化NotificationsWorker。已确认POST_NOTIFICATIONS权限正常,应用目标API为33。

错误日志

Could not instantiate com.example.myapp.ui.notifications.NotificationsWorker
java.lang.NoSuchMethodException: com.example.myapp.ui.notifications.NotificationsWorker.<init> [class android.content.Context, class androidx.work.WorkerParameters]
    at java.lang.Class.getConstructor0(Class.java:2363)
    at java.lang.Class.getDeclaredConstructor(Class.java:2201)
    at androidx.work.WorkerFactory.createWorkerWithDefaultFallback(WorkerFactory.java:95)
    at androidx.work.impl.WorkerWrapper.runWorker(WorkerWrapper.java:243)
    at androidx.work.impl.WorkerWrapper.run(WorkerWrapper.java:145)
    at androidx.work.impl.utils.SerialExecutorImpl$Task.run(SerialExecutorImpl.java:96)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
    at java.lang.Thread.run(Thread.java:1012)
Could not create Worker com.example.myapp.ui.notifications.NotificationsWorker

相关代码

NotificationsWorker.kt

class NotificationsWorker(
    context: Context,
    workerParameters: WorkerParameters,
    private val repository: MyRepository
): CoroutineWorker(context, workerParameters) {

    override suspend fun doWork(): Result {

        val intent = Intent(applicationContext, MainActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
        }

        val pendingIntent: PendingIntent = PendingIntent.getActivity(
            applicationContext, 0, intent, PendingIntent.FLAG_IMMUTABLE
        )

        val today = LocalDate.now()
        var dailyItem = ""
        repository.getDailyItem(today).collect {
            dailyItem = it.title
        }

        val builder = NotificationCompat.Builder(applicationContext, "myChannelId")
            .setSmallIcon(R.drawable.icon)
            .setContentTitle(dailyItem)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setContentIntent(pendingIntent)

        with(NotificationManagerCompat.from(applicationContext)) {
            if (ActivityCompat.checkSelfPermission(
                    applicationContext,
                    Manifest.permission.POST_NOTIFICATIONS
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                    ActivityCompat.requestPermissions(
                        MainActivity(),
                        arrayOf(Manifest.permission.POST_NOTIFICATIONS),
                        1
                    )
                }
            }

            notify(1, builder.build())
        }

        return Result.success()
    }
}

NotificationsScheduler.kt

class NotificationsScheduler @Inject constructor(@ApplicationContext private val context: Context) {

    fun scheduleNotification(hourOfDay: Int, minute: Int) {
        val now = Calendar.getInstance()
        val target = Calendar.getInstance().apply {
            set(Calendar.HOUR_OF_DAY, hourOfDay)
            set(Calendar.MINUTE, minute)
        }

        val timeDiff = target.timeInMillis - now.timeInMillis

        val notificationRequest = PeriodicWorkRequestBuilder<NotificationsWorker>(15, TimeUnit.MINUTES)
            .addTag("daily_item")
            .build()

        WorkManager.getInstance(context)
            .enqueueUniquePeriodicWork(
                "myapp_notification_work",
                ExistingPeriodicWorkPolicy.UPDATE,
                notificationRequest
            )
    }
}

解决方案

1. 核心问题定位

WorkManager默认通过反射实例化Worker,要求Worker必须提供仅接收Context和WorkerParameters两个参数的构造函数。当前NotificationsWorker额外添加了MyRepository参数,导致反射找不到符合要求的构造函数,抛出NoSuchMethodException。

2. 用Hilt正确注入Worker依赖

要在Worker中使用Hilt注入依赖,需遵循以下步骤:

步骤1:修改NotificationsWorker

添加@HiltWorker注解,并用@Assisted标注构造函数的Context和WorkerParameters参数:

import dagger.hilt.android.workers.HiltWorker
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import android.content.Context

@HiltWorker
class NotificationsWorker @AssistedInject constructor(
    @Assisted context: Context,
    @Assisted workerParameters: WorkerParameters,
    private val repository: MyRepository
) : CoroutineWorker(context, workerParameters) {

    override suspend fun doWork(): Result {
        val intent = Intent(applicationContext, MainActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
        }

        val pendingIntent: PendingIntent = PendingIntent.getActivity(
            applicationContext, 0, intent, PendingIntent.FLAG_IMMUTABLE
        )

        val today = LocalDate.now()
        // 改用firstOrNull()避免Flow无限制挂起
        val dailyItem = repository.getDailyItem(today).firstOrNull()?.title ?: "今日无内容"

        val builder = NotificationCompat.Builder(applicationContext, "myChannelId")
            .setSmallIcon(R.drawable.icon)
            .setContentTitle(dailyItem)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setContentIntent(pendingIntent)

        with(NotificationManagerCompat.from(applicationContext)) {
            // 已确认权限正常,移除错误的权限请求逻辑
            notify(1, builder.build())
        }

        return Result.success()
    }
}

步骤2:创建HiltWorkerFactory

让Hilt管理Worker的实例化:

import androidx.work.ListenableWorker
import androidx.work.WorkerFactory
import androidx.work.WorkerParameters
import android.content.Context
import javax.inject.Inject
import javax.inject.Provider
import javax.inject.Singleton

@Singleton
class HiltWorkerFactory @Inject constructor(
    private val workerFactories: Map<Class<out ListenableWorker>, @JvmSuppressWildcards Provider<ChildWorkerFactory>>
) : WorkerFactory() {
    override fun createWorker(
        appContext: Context,
        workerClassName: String,
        workerParameters: WorkerParameters
    ): ListenableWorker? {
        val workerClass = Class.forName(workerClassName).asSubclass(ListenableWorker::class.java)
        return workerFactories[workerClass]?.get()?.create(appContext, workerParameters)
    }
}

interface ChildWorkerFactory {
    fun create(appContext: Context, params: WorkerParameters): ListenableWorker
}

步骤3:在Application中配置WorkManager

指定WorkManager使用HiltWorkerFactory:

import android.app.Application
import androidx.work.Configuration
import dagger.hilt.android.HiltAndroidApp
import javax.inject.Inject

@HiltAndroidApp
class MyApp : Application(), Configuration.Provider {
    @Inject
    lateinit var workerFactory: HiltWorkerFactory

    override fun getWorkManagerConfiguration(): Configuration {
        return Configuration.Builder()
            .setWorkerFactory(workerFactory)
            .build()
    }
}

3. 额外修复点

  • 移除Worker中ActivityCompat.requestPermissions(MainActivity(), ...):Worker是后台组件,不能直接实例化Activity来请求权限,且已确认权限正常,无需保留该逻辑。
  • 将repository.getDailyItem(today).collect改为firstOrNull():Room返回的Flow若为单条数据,collect会一直挂起直到Flow关闭,改用firstOrNull()可获取数据后立即返回,避免不必要的挂起。

内容的提问来源于stack exchange,提问作者zkvvoob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 07:02:04