Featured in Android Weekly Issue #624
In this house, we still use plain Dagger2. It’s… not going great.
Consider the predicament of a composable that can only work with certain parameters:
Sometimes, composables are just asking too much from callers.
By that point, we are probably in-too-deep to change that without breaking 10 other things in the process.
Housekeeping
The goal of this post is to figure out how to create independent composables that can:
Create their own Dagger component
Inject themselves
Build a ViewModel with a custom factory.
- For more information on ViewModels and compose, check out this meme/blog
TL;DR
Starting point
With Dagger2, the activity/fragment normally:
Builds its own Dagger component
Or grabs some dependencies from the application component
It would then pass dependencies downstream to composables as parameters (as they are or via functions):
Information can also be passed down as CompositionLocals.
That approach is debatable, to say the least, and will not be explored in this post.
Migration
In order to make FirstScreen independent, we will need to isolate the injected dependencies into a separate class.
The @Stable annotation will help the compose compiler know that this class will not really change after it has been created.
The Dagger component
The compose layer
While this initially works, it will also create the Dagger component again on every single recomposition.
For an innocent example like this one, it would barely be a hit on performance. Not so for more complex screens.
Let’s use the classic remember keyword, then:
Should someone actually do this?
This approach goes against most compose guidelines. Composables should really be pure functions, fast, idempotent, and free of side effects.
But, when major refactoring is not really feasible, this will get things working without too much effort.
Don’t forget (sorry😑)
If efficiency is paramount, remember will not really cut it. Ian Lake explains why here:
remember is *not* enough of a signal to survive being removed from the Compose hierarchy i.e., when you are on the back stack
In cases such as the above, the DI component will be recreated and injected into the composable again.
It’s not the end of the world, but it is a drawback — especially for heavy Dagger components.
There are 2 options for more advanced scoping if you are worried of losing remember values too easily:
- From sebaslogen. Works great 👍
- From Slack. It does way more things than just a more powerful remember variation. I have no personal experience with this one
Anyways
Hope you found this somewhat useful.
Later.
Comments