https://kotlinlang.org logo
#compose
Title
# compose
r

Robert Menke

09/09/2020, 4:05 PM
Apologize if this has been asked a million times. Is it common to use dependency injection with something like Hilt with Compose? In @Leland Richardson [G]’s example in “Thinking in Compose” it looks like compose already has a helper function called
viewModel
that will provide a properly scoped view model. This looks great, but my concern is that for testing purposes if I want to create a fake for a service that makes a network call and then inject it into my view model I still need something like Hilt. Is there a recommended best practice or tutorial for dependency injection with compose?
r

Ray Ryan

09/09/2020, 4:08 PM
I haven’t really been Composing yet, but it seems to me you should be able to inject things that provide @Composable functions. And that it would be very wise to resist the urge to abuse Ambients instead.
☝️ 3
s

satyan

09/09/2020, 4:15 PM
Technically, you will also tend to inject stuff in your top-level composable, the one that are going to be stateful and will require to do some work (such work should be kept minimal and delegated as much as possible to a view model). So I would argue that you can handle injection by passing things as composable function arguments 🤷
r

Robert Menke

09/09/2020, 4:38 PM
That would mean your top level composable would have to accept every view model in your entire application though which doesn’t seem like a great solution. I do see in JetCaster there’s an example of a dependency graph here https://github.com/android/compose-samples/blob/master/Jetcaster/app/src/main/java/com/example/jetcaster/Graph.kt.
but I don’t think there’s any way to do field injection inside of a function with hilt, so I’m not sure how to proceed 🤔 .
i

Ian Arbuckle

09/09/2020, 7:06 PM
Why would be it useful to inject dependencies to Composable functions? Aren't they better best left as stateless and driven from the outside i.e. view model.
r

Robert Menke

09/09/2020, 7:53 PM
The current approach to loading view models won’t allow you to use hilt’s DI system AFAIK, so injecting something like an outside service into your viewmodel via hilt wouldn’t work properly if I understand correctly.
i

Ian Arbuckle

09/09/2020, 8:29 PM
I used Hilt with Compose and found no issues. I've only passed in a view model to my top level Composable function. https://github.com/IanArb/RickMortyComposeSample/blob/master/app/src/main/java/com/ianarbuckle/rickmortycompose/HomeActivity.kt
r

Robert Menke

09/09/2020, 8:36 PM
But if you had an application with a lot of view models you would have had to pass in every view model to your top level composable, no?
i

Ian Arbuckle

09/09/2020, 8:45 PM
You can pass it to any Composable given it is injected from an activity/fragment. But yeah, if you are doing single activity approach, the activity would end up injecting too many view models. It's still early days and I'm sure Google are aware of architectural limitations
r

Ray Ryan

09/10/2020, 3:18 PM
Single Activity or Die
z

Zach Klippenstein (he/him) [MOD]

09/10/2020, 4:57 PM
I don’t think our DI instincts from classic Android development are necessarily directly applicable to Compose, at least not in the same way. https://kotlinlang.slack.com/archives/CJLTWPH7S/p1594385570100600?thread_ts=1594338382.091800&cid=CJLTWPH7S Also, as @Ray Ryan pointed out, if you really want to make a class that injects stuff and has a composable method, you can do that too.
1
s

satyan

09/10/2020, 6:44 PM
@Zach Klippenstein (he/him) [MOD] the only place nail I would want to put a nail on is the view model from jetpack. View model (jetpacks ones) provides several benefits: - a boundary between UI and business logic - a scope (if I'm loading article on screen A and the user go back or elsewhere I want to stop loading or at least ignore the result) - saving state (configuration change) Being boundaries to the business logic, you need to inject business logic in the view model (use cases or repositories). If you need to inject business logic in a view model you need to be able to inject a view model factory (manual one or using assisted inject) in screens. You could create classes for those screens to inject the view model factory (plus formatters, trackers, loggers, ...). If you only have callbacks and pure data in composable functions you will require to handle manually those three concerns (which isn't a bad or good thing 🤷‍♀️).
r

Robert Menke

09/11/2020, 1:28 AM
So to be clear what I’m after is A) Use compose as the primary UI pattern (without resorting to activities/fragments if possible) B) Swap out dependencies of composable functions for testing It seems like this isn’t currently possible without resorting to multiple activities or passing a large number of parameters to each composable function.
z

Zach Klippenstein (he/him) [MOD]

09/11/2020, 2:36 PM
It's hard to say without specific code to talk about, but usually the solution to "a large number of parameters" is to accept a slot (a composable function) instead of hard-coding the composable content.
r

Robert Menke

09/11/2020, 2:41 PM
I think I got it working actually - was just being dumb (like most of my programming issues 😅 )
r

Ray Ryan

09/11/2020, 3:20 PM
That’s how you can tell it’s programming.
💯 1