2

How would the @Composable ContentFeed() function access the viewModel which was created in the Activity? Dependency injection? Or is that a wrong way of doing things here? The viewModel should always have only have one instance.

// MainActivity.kt
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val viewModel by viewModels<MainViewModel>()
        setContent {
        PracticeTheme {
            // A surface container using the 'background' color from the theme
            Surface(color = MaterialTheme.colors.background) {
                PulseApp(viewModel)
            }
        }
    }
}

// TabItem.kt
typealias ComposableFun = @Composable () -> Unit

sealed class TabItem(var icon: Int, var title: String, var content: ComposableFun) {
    object Feed : TabItem(R.drawable.ic_baseline_view_list_24, "Feed", { ContentFeed() })
}

// Content.kt
@Composable
fun ContentFeed() {
    // I need viewModel created in MainActivity.kt here
}
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
xlog
  • 103
  • 13

1 Answers1

5

In any composable you can use viewModel<YourClassHere>():

Returns an existing ViewModel or creates a new one in the given owner (usually, a fragment or an activity), defaulting to the owner provided by LocalViewModelStoreOwner.

The only exception in Compose for now, when it's not bind to activity/fragment, is when you're using Compose Navigation. In this case the store owner is bind to each route, see this and this answers on how you can share store owners between routes.

Check out more about view models Compose in documentation.

Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
  • Oh wow, I can't believe I missed that. What I've been doing so far is initializing the `ViewModel` in the `onCreate()` method of an activity and passing it down to all functions as an argument. So I should have just been doing instead is `val viewModel = viewModel()` in all the Composable functions that require that specific `viewModel` correct? – xlog Dec 14 '21 at 08:44
  • 2
    @xlog correcty, you don't need to initialize anything in the activity. View model will be created when you need it – Phil Dukhov Dec 14 '21 at 11:28
  • @xlog `We recommend screen-level composables use ViewModel instances for providing access to business logic and being the source of truth for their UI state. You should not pass ViewModel instances down to other composables.`. https://developer.android.com/jetpack/compose/state#viewmodels-source-of-truth – Dr.jacky May 31 '22 at 18:54
  • @Dr.jacky "You should not" - this is more like architecture advice, there's no technical problems in doing so, but yes, not passing VM is making your code cleaner. Also screen here is not related to activity or fragment, it can be Compose Navigation route view. – Phil Dukhov Jun 01 '22 at 04:22