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!!
Stay organized with collections Save and categorize content based on your preferences. To get started using WorkManager, first import the library into your Android project. Once you've added the dependencies and synchronized your Gradle project, the next step is to define some work to run.
Android WorkManager is a background processing library which is used to execute background tasks which should run in a guaranteed way but not necessarily immediately. With WorkManager we can enqueue our background processing even when the app is not running and the device is rebooted for some reason.
WorkManager PoliciesKEEP — keeps the existing unfinished WorkRequest. Enqueues it if one does not already exist. REPLACE — always replace the WorkRequest. Cancels and deletes the old one, if it exists.
Use WorkManager for reliable workWorkManager is intended for work that is required to run reliably even if the user navigates off a screen, the app exits, or the device restarts. For example: Sending logs or analytics to backend services. Periodically syncing application data with a server.
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 of 1.0.0-alpha10
that is no longer an option.
Let's say that you have a Worker
subclass called DataClearingWorker
, and that this class needs a Foo
from your Dagger graph.
class DataClearingWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) { lateinit var foo: Foo override fun doWork(): Result { foo.doStuff() return Result.SUCCESS } }
Now, you can't just instantiate one of those DataClearingWorker
instances directly. So you need to define a WorkerFactory
subclass that can create one of them for you; and not just create one, but also set your Foo
field too.
class DaggerWorkerFactory(private val foo: Foo) : WorkerFactory() { override fun createWorker(appContext: Context, workerClassName: String, workerParameters: WorkerParameters): ListenableWorker? { val workerKlass = Class.forName(workerClassName).asSubclass(Worker::class.java) val constructor = workerKlass.getDeclaredConstructor(Context::class.java, WorkerParameters::class.java) val instance = constructor.newInstance(appContext, workerParameters) when (instance) { is DataClearingWorker -> { instance.foo = foo } // optionally, handle other workers } return instance } }
Finally, you need to create a DaggerWorkerFactory
which has access to the Foo
. You can do this in the normal Dagger way.
@Provides @Singleton fun workerFactory(foo: Foo): WorkerFactory { return DaggerWorkerFactory(foo) }
You'll also need to disable the default WorkManager
initialization (which happens automatically) and initialize it manually.
How you do this depends on the version of androidx.work
that you're using:
In AndroidManifest.xml
, add:
<provider android:name="androidx.startup.InitializationProvider" android:authorities="YOUR_APP_PACKAGE.androidx-startup" android:exported="false" tools:node="merge"> <meta-data android:name="androidx.work.WorkManagerInitializer" android:value="androidx.startup" tools:node="remove" /> </provider>
In AndroidManifest.xml
, add:
<provider android:name="androidx.work.impl.WorkManagerInitializer" android:authorities="YOUR_APP_PACKAGE.workmanager-init" android:enabled="false" android:exported="false" tools:replace="android:authorities" />
Be sure to replace YOUR_APP_PACKAGE with your actual app's package. The <provider
block above goes inside your <application
tag.. so it's a sibling of your Activities
, Services
etc...
In your Application
subclass, (or somewhere else if you prefer), you can manually initialize WorkManager
.
@Inject lateinit var workerFactory: WorkerFactory private fun configureWorkManager() { val config = Configuration.Builder() .setWorkerFactory(workerFactory) .build() WorkManager.initialize(this, config) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With