Injecting Repository in WorkManager's Worker

Viewed 3776

The Use-Case: I need to take feedback from users, save it in the persistent storage, in this case its Room. And after every X minutes I want to send these stored FeedbackRequest to the backend.

The Solution: I thought of using WorkManager since this action should survive the process death & also be triggered periodically. I need to get the list of FeedbackRequest from Room DB & use Retrofit client to send every FeedbackRequest to the backend.

The Problem-Definition: FeedbackRequestRepository, which is responsible for getting the list of FeedbackRequest, is required in the doWork() method of WorkManager to get the data from Room DB. Also, I am pretty new to Dagger2. I am getting the mentioned error after the app open.

AppComponent Code Snippet

interface AppComponent {
@Component.Builder
interface Builder {
    @BindsInstance
    fun application(application: Application): Builder

    fun build(): AppComponent
}

fun inject(scFeedbackApp: ScFeedbackApp)
fun inject(dispatchWorker: DispatchWorker)

}

Repository Code Snippet

@Singleton
class FeedbackRequestRepository @Inject constructor(
        private val appExecutors: AppExecutors,
        private val db: ScFeedbackDB,
        private val feedbackAcknowledgeDao: FeedbackRequestDao,
        private val scFeedbackFeedbackService: SCFeedbackService
) {

...

}

Worker Code Snippet

class DispatchWorker @Inject constructor(context:Context,
                             workerParameters: WorkerParameters,
                             var feedbackRequestRepository: FeedbackRequestRepository):
    Worker(context, workerParameters){
init {
    DaggerAppComponent.builder().application(context.applicationContext as ScFeedbackApp)
            .build().inject(this)
}
override fun doWork(): Result {

...

}

Error

E/WorkerFactory: Could not instantiate com.scfeedback.service.responseDispatcher.DispatchWorker
java.lang.NoSuchMethodException: <init> [class android.content.Context, class androidx.work.WorkerParameters]
    at java.lang.Class.getConstructor(Class.java:528)
    at java.lang.Class.getDeclaredConstructor(Class.java:507)
    at androidx.work.WorkerFactory.createWorkerWithDefaultFallback(WorkerFactory.java:85)
    at androidx.work.impl.WorkerWrapper.runWorker(WorkerWrapper.java:188)
    at androidx.work.impl.WorkerWrapper.run(WorkerWrapper.java:124)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
    at java.lang.Thread.run(Thread.java:818)
E/WorkerWrapper: Could not create Worker com.scfeedback.service.responseDispatcher.DispatchWorker
  1. Does this have something to do with Dependency Inject setting.
  2. If not, then where am I going wrong.
1 Answers

There are two problems with your approach:

  • You can't apply both constructor injection @inject constructor(...) and direct injection DaggerAppComponent...inject(this)
  • You must use the default constructor:

So you can change your DispatchWorker to:

    class DispatchWorker constructor(context:Context,
                                 workerParameters: WorkerParameters):
        Worker(context, workerParameters){

        @Inject  lateinit var feedbackRequestRepository: FeedbackRequestRepository

    init {
        DaggerAppComponent.builder().application(context.applicationContext as ScFeedbackApp)
                .build().inject(this)
    }
    override fun doWork(): Result {

    ...

}

Or use a custom WorkerFactory

Related