top of page

Injecting Composables with Dagger without losing it





 


Everyone is using Hilt/Koin or some other fancy DI framework that just works™.


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.

Commentaires


bottom of page