So from what I read, Dagger doesn't have support for inject in Worker yet. But there are some workarounds as people suggest. I have tried to do it a number of ways following examples online but none of them work for me.
When I don't try to inject anything into the Worker class, the code works fine, only that I can't do what I want because I need access to some DAOs and Services. If I use @Inject on those dependencies, the dependencies are either null or the worker never starts i.e the debugger doesn't even enter the Worker class.
For eg I tried doing this:
@Component(modules = {Module.class})
public interface Component{
void inject(MyWorker myWorker);
}
@Module
public class Module{
@Provides
public MyRepository getMyRepo(){
return new myRepository();
}
}
And in my worker
@Inject
MyRepository myRepo;
public MyWorker() {
DaggerAppComponent.builder().build().inject(this);
}
But then the execution never reaches the worker. If I remove the constructor, the myRepo dependency remains null.
I tried doing many other things but none work. Is there even a way to do this? Thanks!!
I use Dagger2 Multibindings to solve this problem.
The similar approach is used to inject
ViewModel
objects (it's described well here). Important difference from view model case is the presence ofContext
andWorkerParameters
arguments inWorker
constructor. To provide these arguments to worker constructor intermediate dagger component should be used.Annotate your
Worker
's constructor with@Inject
and provide your desired dependency as constructor argument.Create custom annotation that specifies the key for worker multibound map entry.
Define worker binding.
Define intermediate component along with its builder and module which will provide
Context
andWorkerParameters
objects. The component must have the method to get workers map from dependency graph and contain worker binding module among its modules. Also the component must be declared as a subcomponent of its parent component and parent component must have the method to get the child component's builder.Implement
WorkerFactory
. It will create the intermediate component, get workers map, find the corresponding worker provider and construct the requested worker.Initialize a
WorkManager
manually with custom worker factory (it must be done only once per process). Don't forget to disable auto initialization in manifest.manifest:
Application
onCreate
:Use worker
Watch this talk for more information on
WorkManager
features.As of version 1.0.0-beta01, here is an implementation of Dagger injection with WorkerFactory.
The concept is from this article: https://medium.com/@nlg.tuan.kiet/bb9f474bde37 and I just post my own implementation of it step by step(in Kotlin).
===========
What's this implementation trying to achieve is:
Every time you want to add a dependency to a worker, you put the dependency in the related worker class
===========
1. Add an interface for all worker's factory
IWorkerFactory.kt
2. Add a simple Worker class with a Factory which implements IWorkerFactory and also with the dependency for this worker
HelloWorker.kt
3. Add a WorkerKey for Dagger's multi-binding
WorkerKey.kt
4. Add a Dagger module for multi-binding worker (actually multi-binds the factory)
WorkerModule.kt
5. Put the WorkerModule into AppComponent. Here I use dagger-android to construct the component class
AppComponent.kt
6. Add a custom WorkerFactory to leverage the ability of creating worker since the release version of 1.0.0-alpha09
DaggerAwareWorkerFactory.kt
7. In Application class, replace WorkerFactory with our custom one:
App.kt
8. Don't forget to disable default work manager initialization
AndroidManifest.xml
That's it.
Every time you want to add a dependency to a worker, you put the dependency in the related worker class (like HelloWorker here).
Every time you want to add a worker, implement the factory in the worker class and add the worker's factory to WorkerModule for multi-binding.
For more detail, like using AssistedInject to reduce boilerplate codes, please refer to the article I mentioned at beginning.
Overview
You need to look at WorkerFactory, available from
1.0.0-alpha09
onwards.Previous workarounds relied on being able to create a
Worker
using the default 0-arg constructor, but as of1.0.0-alpha10
that is no longer an option.Example
Let's say that you have a
Worker
subclass calledDataClearingWorker
, and that this class needs aFoo
from your Dagger graph.Now, you can't just instantiate one of those
DataClearingWorker
instances directly. So you need to define aWorkerFactory
subclass that can create one of them for you; and not just create one, but also set yourFoo
field too.Finally, you need to create a
DaggerWorkerFactory
which has access to theFoo
. You can do this in the normal Dagger way.Disabling Default WorkManager Initialization
You'll also need to disable the default
WorkManager
initialization (which happens automatically) and initialize it manually.In the
AndroidManifest.xml
, you can disable it like this:Be sure to replace com.your.app.package with your actual app's package. The
<provider
block above goes inside your<application
tag.. so it's a sibling of yourActivities
,Services
etc...In your
Application
subclass, (or somewhere else if you prefer), you can manually initializeWorkManager
.In WorkManager
alpha09
there is a new WorkerFactory that you can use to initialize theWorker
the way you want to.Worker
constructor which takes in anApplicationContext
andWorkerParams
.WorkerFactory
viaConfiguration
.configuration
and register the newly createdWorkerFactory
.WorkManager
with this configuration (while removing theContentProvider
which initializesWorkManager
on your behalf).You need to do the following: