Illustration by Virginia Poltrack

Customizing WorkManager with Dagger

Pietro Maggi
Android Developers
Published in
4 min readApr 4, 2020

--

Welcome to the sixth post of our WorkManager series. WorkManager is an Android Jetpack library that runs deferrable, guaranteed background work when the work’s constraints are satisfied. It is the current best practice for this kind of work on Android.

If you’ve been following thus far, we’ve talked about:

In this blog post, we’re going to talk about custom configuration with Dagger, covering:

  • Using Dagger to inject parameters in our WorkerFactory
  • On-Demand initialization

⚠️ This article expands on the last one on customizing WorkManager. I strongly suggest that you take a look at it before diving into this one!

Why Dagger

Dagger is the Dependency Injection library of choice for Android development. It is under active development by Google. If you’ve never used it or want to learn more about it, you can take a look at the guide or use the codelab to get familiar with it.

In this blog post I will assume that you already have some familiarity with this library and with the concept of dependency injection in general.
If you use another Dependency Injection library (or no library at all) the concepts presented in this article will still be useful.

Recap

In the previous article we covered how to customise WorkManager, including how to use a DelegatingWorkerFactory, to pass additional parameters into your workers. It is now time to see how to use Dagger to inject these parameters.

Inject parameters into a WorkerFactory with Dagger

You need to integrate Dagger in your WorkerFactory if you are already using it to manage your dependencies. If you’re using Dagger to pass a reference to a Retrofit service in your application, and you want to pass this into your worker, then Dagger needs to inject this reference into the custom WorkerFactory, so it can create your workers using it as an additional parameter.

Let’s imagine that this time we have the Retrofit service reference injected by Dagger. This is not going to change the need to have a custom factory and a custom configuration for WorkManager. Simply, this new parameter will now be injected in our factory by Dagger.

⚠️ for Dagger to be able to inject this value, we need to have it in the Dagger graph and that’s why we annotate the Factory with @Inject.

In this sample we set up Dagger in the Application with an AppComponent that we then initialize in MyApplication to perform member injection from Dagger:

In the Application class we can then inject our component:

Since Dagger knows how to provide instances of MyWorkerFactory, you can get the instance from the Dagger graph using @Inject and use it in the getWorkManagerConfiguration method:

Everything else in our project stays the same.

A real world example

Dagger really shines in a medium/large database. We updated iosched, the Google I/O and Android Dev Summit scheduling app, to use WorkManager and Dagger.

In the iosched release for the Android Developer Summit 2019, JobScheduler was replaced with WorkManager for the forced update of the schedule. This feature was added in case we need to push an urgent update of the schedule to devices.

In this case the additional parameter we need to use in our Worker is refreshEventDataUseCase. You can take a look at the commit that introduced this feature on github’s iosched repository, in the ADSsched branch.

Let’s take a look at the most important pieces starting with the worker itself:

ConferenceDataWorker.kt

Source: ConferenceDataWorker.kt

As you can see, there’s no Dagger annotation on our Worker classes, as the passing of the parameter is handled at the WorkerFactory level.

This parameter is something that Dagger already knows, so it would be possible to inject this directly in our custom WorkerFactory:

Source: ConferenceDataWorkerFactory.kt

Wait. Still no Dagger annotation here… The reason is that we use a DelegatingWorkerFactory to coordinate all the single factories (we just have one at this moment in IOsched, but we built it in a way that it is straightforward to add more if needed):

IoschedWorkerFactory.kt

Source: IoschedWorkerFactory.kt

Ok, here is where we are injecting our constructor’s parameters with Dagger.

In this application we decided to use on-demand initialization and we are using Dagger to inject the whole configuration:

Source: MainApplication.kt

This allows us to inject a different configuration for different build types. In particular, we are injecting a configuration with the log level set to DEBUG for the debug build:

Source: debugRelease SharedModule.kt

Meanwhile the release build is just setting the custom factory using the default debug level:

SharedModule.kt (in shared/src/staging/j/c/g/s/a/i/shared/di/)

Source: staging SharedModule.kt

WorkManager will be initialized on-demand the first time we retrieve its instance. This is going to happen when we receive the Firebase message to retrieve a new schedule:

IoschedFirebaseMessagingService.kt

Source: IoschedFirebaseMessagingService.kt

This concludes our exploration of how Dagger can be used to inject parameters into your workers. We have also seen how WorkManager can be integrated in a larger application like iosched.

Conclusions

WorkManager is a powerful library, able to cover a lot of common use cases with its default configuration. However there are some cases when you need to increase its debugging level or need to pass additional parameters to your worker. In these cases you need a custom configuration.

I hope these latest two articles have given you a good overview of this topic, let me know if you have any questions in the comments or contacting me directly on twitter at pfmaggi@.

Happy coding!

--

--