WorkManager with Android Libraries
WorkManager
is a powerful jetpack library for persistent work. Scheduled work is guaranteed to be executed sometime after its constraints
(like metered network, the battery charging, etc.) are met. WorkManager
allows observation of work status and the ability to create a complex chain of work.
There are numerous blogs and tutorials available for WorkManager
usage in android applications with WorkManager
initialization at the app startup time or on-demand initialization like the one below
But very few are available on how to use WorkManager
in the right way within a SDK.
If workers
have custom dependencies, then we have to provide the WorkerFactory
to the WorkManager
through which it will do the initialization of workers.
WorkerFactory
we have to provide at the time of initialization of the singleton WorkManager
. You can read more about WorkManager
custom initialization here.
The problem comes when we want to use the WorkManager
in the android library like-
WorkManager
is a singleton. So it can be initialized only once, either in-app or in the library.- If you are using
workers
with custom dependencies, then you have to provide aWorkerFactory
to theconfiguration
at the time of custom initialization. This can be adelegatingWorkerFactory
which delegates to other factories, but all factories still need to register with the single delegator. We have to expose theWorkerFactory
to the app so that it can be used at the time of initialization.
We had the same set of issues while working in my current organization, Rapido.
We are developing an SDK (comms-SDK
) for facilitating communication between the platform and the apps which will be used in the Rider
(we call them Captain) app wherein we are periodically syncing data to the server, for that purpose, we used an WorkManager
in the library.
We don't want to enforce our apps (which use comms-SDK
) to use WorkManager,
and they should not know the internal implementation of the library (WorkerFactory).
While finding the solution to this problem, we landed on the awesome square team blog where they also had a similar issue with their logging SDK.
Let's go to the solution now.
Problem 1: WorkManager initialization(w.r.to the app using our library)
Solution: For this, the solution was simple, we try to get the instance of WorkManager
in the library, if we get an exception like
Caused by: java.lang.IllegalStateException: WorkManager is not initialized properly. The most likely cause is that you disabled WorkManagerInitializer in your manifest but forgot to call WorkManager#initialize in your Application#onCreate or a ContentProvider.
Then only initialize the WorkManager
in the library.
Problem 2: Launching Workers
with custom dependencies from the library.
Solution: If we dig deeper into the WorkManager
code, we can see that if WorkerFactory
is not provided at the time of initialization of the WorkManager
for a particular Worker,
then it uses the default WorkerFactory
which initializes the Workers
via reflection until it has no custom dependencies.
if (builder.mWorkerFactory == null) {
mWorkerFactory = WorkerFactory.getDefaultWorkerFactory();
} else {
mWorkerFactory = builder.mWorkerFactory;
}
This means we can create another worker (say, ProxyWorker
) with no custom dependency, which will be invoked by WorkManager,
and we can use this Worker
to invoke other Workers
with custom dependency in the library via delegateWorkerFactory
.
ProxyWorker
can be configured like this:
We can schedule and stop the ProxyWorker
in this way:
And that’s it. Now WorkManager
will work independently with the app using your library.
I would like to thank Puneet, for the guidance and feedback.
That’s it for now, hope it helps! Enjoy and feel free to leave a comment if something is not clear or if you have questions. Thank you for reading! 🙌🙏