gaohomway
gaohomway

Reputation: 4080

Create multiple view model instances in Jetpack Compose

We know that the following way to create an instance is very good, you can enjoy life cycle management. And the instances created in an ViewModel are the same.

But if you want to create two instances on one page, how to create it?

fun Following(viewModel: FollowViewModel = viewModel()) {

}

Upvotes: 5

Views: 2777

Answers (2)

Roberto Leinardi
Roberto Leinardi

Reputation: 14449

If you use Dagger Hilt, the support to the key is added via the AndroidX artifact androidx.hilt:hilt-navigation-compose.

Alternatively you can create yourself this inline function:

import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.hilt.navigation.HiltViewModelFactory
import androidx.lifecycle.HasDefaultViewModelProviderFactory
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
import androidx.lifecycle.viewmodel.compose.viewModel

/**
 * Returns an existing
 * [HiltViewModel](https://dagger.dev/api/latest/dagger/hilt/android/lifecycle/HiltViewModel)
 * -annotated [ViewModel] or creates a new one scoped to the current navigation graph present on
 * the {@link NavController} back stack.
 *
 * If no navigation graph is currently present then the current scope will be used, usually, a
 * fragment or an activity.
 *
 * @sample androidx.hilt.navigation.compose.samples.NavComposable
 * @sample androidx.hilt.navigation.compose.samples.NestedNavComposable
 */
@Composable
inline fun <reified VM : ViewModel> hiltViewModel(
    viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) {
        "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner"
    },
    key: String? = null
): VM {
    val factory = createHiltViewModelFactory(viewModelStoreOwner)
    return viewModel(viewModelStoreOwner, key, factory = factory)
}

@Composable
@PublishedApi
internal fun createHiltViewModelFactory(
    viewModelStoreOwner: ViewModelStoreOwner
): ViewModelProvider.Factory? = if (viewModelStoreOwner is HasDefaultViewModelProviderFactory) {
    HiltViewModelFactory(
        context = LocalContext.current,
        delegateFactory = viewModelStoreOwner.defaultViewModelProviderFactory
    )
} else {
    // Use the default factory provided by the ViewModelStoreOwner
    // and assume it is an @AndroidEntryPoint annotated fragment or activity
    null
}

Upvotes: 0

Phil Dukhov
Phil Dukhov

Reputation: 88222

You can use key argument which is used to identify the ViewModel:

val firstViewModel = viewModel<FollowViewModel>(key = "first")
val secondViewModel = viewModel<FollowViewModel>(key = "second")

p.s. If you are using Hilt, hiltViewModel does not yet support keys, you can star this feature request for updates, and check out hack in this answer for now.

Upvotes: 14

Related Questions