We’re adding the use of dynamic feature modules to our app. This will help us to improve build speeds, conditionally include features and decouple our code. As noted previously, we make use of Dagger Multibinding and the Android Job library to handle our background tasks.
When we created our first feature module we ran into an issue when we attempted to move the associated Job
classes. Let me walk you through the problem, the solution we settled on and then proposed next steps.
The Problem
Inside of the app
module we have our JobManager
. Its job is to schedule requests, like this:
When a request is received, the JobManager
attempts to create a new instance of the desired Job
. It does this by means of a JobCreator
. The JobCreator
holds a multi-bound map which it inspects in order to create a new Job
, like this:
And finally, we have a Dagger Module that contains all of the Job
bindings so that they can be grouped together in a multi-bound map:
Initially, we created a new Dagger Module for the Job
s that belonged to a particular feature. However, since we didn’t know how to inform the JobCreator
about them, no Job
s were scheduled. We ended up leaving all of the Job
s inside of the main app
module. Not ideal.
The Solution
After lots of digging and trying things out; we settled on the following solution:
- Base Interface in the
app
module that feature modules could implement when they hadJob
s to execute - Separate Dagger Modules and Components in feature modules for
Job
s - The
app
module would use Reflection to create needed classes from feature modules
The first thing we needed to do was create an Interface
to be implemented in each of the feature modules. This allows us to separate the Job
s and their bindings per feature module using Dagger. Further, by means of the JobCreatorProvider
Interface, we can create new instances of JobCreator
classes as needed from the main app
module.
Here’s a sample implementation in the service
module:
In order to get this to work, we needed two new Dagger classes in the service
module: ServiceJobsModule
and ServiceJobsComponent
.
In the ServiceJobsModule
you will see that we’ve defined the binding for a Job
that lives only in the service
module. We’ve also created a binding for our ServiceJobCreator
.
Then in the ServiceJobsComponent
class we just wire up our dependencies.
We’re almost ready to take advantage of this setup. The final step is to modify how we create our JobManager
in the AppModule
. We previously only called the addJobCreator
method once. That’s because all of the Job
s were located in the same JobCreator
‘s multi-bound map.
That’s no longer the case. Instead, we have multiple JobCreator
s potentially available to us from dynamic feature modules. This means that we will need to attempt creating those objects and adding them to our list of JobCreator
s. And then we can use the JobManager
from anywhere in our project and it will know how to find the Job
that needs to be executed.
Here’s a snippet from the final AppModule
class where you can see how this all comes together:
The end result is that now we can store the Jobs
in their respective modules instead of having them all inside of the main app
module. Each feature module has it’s own JobCreator
that knows how to create the enclosed Job
s.
Next Steps
Ideally, I don’t like that we have to have separate JobCreator
s in each module which does essentially the same thing. I would love to be able to only have the distinct Dagger JobsModule
s and then update the primary JobCreator
‘s multi-bound map. I haven’t found a way to do that as of yet.
Resources
If you want to read more about working with dynamic feature modules I would recommend the following resources: