Hi all! I'm new to Compose and was wondering how t...
# compose
t
Hi all! I'm new to Compose and was wondering how the typical ViewModel approach (i.e. one fragment/activity -> one ViewModel) applies to Compose. If my entire app is a single activity that navigates through composables, and each composable would have different data for it's state that is fetched via a coroutine in a ViewModel, would I then inject every single VM I'd need for the whole app inside the Activity? That doesn't seem right.
i
If you are using Navigation Compose (https://developer.android.com/jetpack/compose/navigation), then ViewModels created within one composable screen will automatically be scoped to just that screen
t
Thanks Ian, but I think that example leads to something where we just have a single viewmodel in an Activity that is used as a parameter to the Composable. It just looks to me now that I don't need multiple viewmodels in a single-Activity architecture since I'm no longer using Fragments. Therefore, MainViewModel would be the single access point to launch each and every UseCase I'd need
🤮 1
Yeah I know that sounds terrible 😓 , but I just haven't seen an example of how we're meant to work with different ViewModels within an activity that switches Composables for it's screens
i
I'm not sure I follow. Compose just lets you do
val yourViewModel: YourViewModel = viewModel()
as per the docs: https://developer.android.com/jetpack/compose/interop#viewmodel
And that automatically gets scoped to that single screen if you're using it within Navigation Compose's
NavHost
t
Got it! Thanks for pointing me to the interop section of the docs, that's exactly what I needed to see
i
Also note that activities, fragments, compose, and everywhere else has always supported multiple ViewModels - there's never been a 1:1 requirement
👍 1
t
Of course, that's generally just the pattern I've stuck to, unless there is a need for a shared VM.
r
Is the challenge you’re facing dealing with in-memory state that should live beyond the lifetime of a composable? For example, if I wanted to fetch a profile avatar when my app loads so that it’s always available when I go to my profile tab I may want that Bitmap loaded into memory for the entire lifetime of my application (or at least the URL that I can use to load it). 3 options here as far as I can tell: 1. Use a storage mechanism like Room for anything that needs to persist beyond a composable 2. Use something like hilt to scope your viewmodels 3. Create all the instances you need in your activity and pass them in to your composables in the function call
i
Keep in mind that any image loading library such as Coil, Picasso, Glide, etc. already have an in memory cache
👍 1
☝️ 1
b
@Ian Lake if I understand the current state of affairs, if your ViewModel has any dependencies, you have to roll your own Factory in order to use the compose
viewModel()
extension, right?
Copy code
val vm: MyViewModel = viewModel(factory = MyViewModelFactory)
And if you are using Hilt for DI, then … ??
i
Looks like there's a workaround for Hilt's issue on their tracking bug (since the issue is with what Hilt is doing): https://github.com/google/dagger/issues/2166#issuecomment-723775543
👍 3
t
FWIW, I have been using Koin. Incredibly simple. If I implement each ViewModel as a KoinComponent, I can inject my dependencies into the viewmodel and instantiate the viewmodel in the Composable. https://doc.insert-koin.io/#/koin-core/koin-component