ViewModel Scoping APIs Teil von Android Jetpack.

Der Umfang ist entscheidend, um ViewModels effektiv zu nutzen. Jede ViewModel ist auf ein Objekt beschränkt, das die ViewModelStoreOwner-Schnittstelle implementiert. Es gibt mehrere APIs, mit denen Sie den Bereich Ihrer ViewModels einfacher verwalten können. In diesem Dokument werden einige der wichtigsten Techniken beschrieben, die Sie kennen sollten.

Mit der Methode ViewModelProvider.get() können Sie eine Instanz einer ViewModel-Instanz abrufen, die auf eine beliebige ViewModelStoreOwner beschränkt ist. Für Kotlin-Nutzer stehen verschiedene Erweiterungsfunktionen für die gängigsten Anwendungsfälle zur Verfügung. Bei allen Implementierungen von Kotlin-Erweiterungsfunktionen wird die ViewModelProvider API im Hintergrund verwendet.

ViewModels, die auf den nächstgelegenen ViewModelStoreOwner beschränkt sind

Sie können ein ViewModel auf eine Aktivität, ein Fragment oder ein Ziel eines Navigationsdiagramms festlegen. Mit den Funktionen der Erweiterung viewModels(), die von den Bibliotheken „Activity“, „Fragment“ und „Navigation“ bereitgestellt werden, sowie der Funktion viewModel() in Compose können Sie eine Instanz von ViewModel abrufen, die dem nächstgelegenen ViewModelStoreOwner zugeordnet ist.

Aufrufe

import androidx.activity.viewModels

class MyActivity : AppCompatActivity() {
    // ViewModel API available in activity.activity-ktx
    // The ViewModel is scoped to `this` Activity
    val viewModel: MyViewModel by viewModels()
}

import androidx.fragment.app.viewModels

class MyFragment : Fragment() {
    // ViewModel API available in fragment.fragment-ktx
    // The ViewModel is scoped to `this` Fragment
    val viewModel: MyViewModel by viewModels()
}

Aufrufe

import androidx.lifecycle.ViewModelProvider;

public class MyActivity extends AppCompatActivity {
    // The ViewModel is scoped to `this` Activity
    MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);
}

public class MyFragment extends Fragment {
    // The ViewModel is scoped to `this` Fragment
    MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);
}

Schreiben

import androidx.lifecycle.viewmodel.compose.viewModel

@Composable
fun MyScreen(
    modifier: Modifier = Modifier,
    // ViewModel API available in lifecycle.lifecycle-viewmodel-compose
    // The ViewModel is scoped to the closest ViewModelStoreOwner provided
    // via the LocalViewModelStoreOwner CompositionLocal. In order of proximity,
    // this could be the destination of a Navigation graph, the host Fragment,
    // or the host Activity.
    viewModel: MyViewModel = viewModel()
) { /* ... */ }

ViewModels, die auf einen beliebigen ViewModelStoreOwner beschränkt sind

Die Funktionen ComponentActivity.viewModels() und Fragment.viewModels() im View-System und die viewModel()-Funktion in Compose verwenden einen optionalen ownerProducer-Parameter, mit dem Sie angeben können, auf welche ViewModelStoreOwner die Instanz von ViewModel beschränkt ist. Das folgende Beispiel zeigt, wie Sie eine Instanz einer ViewModel-Instanz abrufen, die auf das übergeordnete Fragment beschränkt ist:

Aufrufe

import androidx.fragment.app.viewModels

class MyFragment : Fragment() {

    // ViewModel API available in fragment.fragment-ktx
    // The ViewModel is scoped to the parent of `this` Fragment
    val viewModel: SharedViewModel by viewModels(
        ownerProducer = { requireParentFragment() }
    )
}

Aufrufe

import androidx.lifecycle.ViewModelProvider;

public class MyFragment extends Fragment {

    SharedViewModel viewModel;

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        // The ViewModel is scoped to the parent of `this` Fragment
        viewModel = new ViewModelProvider(requireParentFragment())
            .get(SharedViewModel.class);
    }
}

Schreiben

import androidx.lifecycle.viewmodel.compose.viewModel

@Composable
fun MyScreen(
    context: Context = LocalContext.current,
    // ViewModel API available in lifecycle.lifecycle-viewmodel-compose
    // The ViewModel is scoped to the parent of the host Fragment
    // where this composable function is called
    viewModel: SharedViewModel = viewModel(
        viewModelStoreOwner = (context as Fragment).requireParentFragment()
    )
) { /* ... */ }

Ein häufiger Anwendungsfall ist das Abrufen eines ViewModel mit Aktivitätsebene aus einem Fragment. Dazu steht die Erweiterungsfunktion activityViewModels() für Ansichten zur Verfügung. Wenn Sie nicht Views und Kotlin verwenden, können Sie dieselben APIs wie oben verwenden und den richtigen Inhaber übergeben.

Aufrufe

import androidx.fragment.app.activityViewModels

class MyFragment : Fragment() {

    // ViewModel API available in fragment.fragment-ktx
    // The ViewModel is scoped to the host Activity
    val viewModel: SharedViewModel by activityViewModels()
}

Aufrufe

import androidx.lifecycle.ViewModelProvider;

public class MyFragment extends Fragment {

    SharedViewModel viewModel;

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        // The ViewModel is scoped to the host Activity
        viewModel = new ViewModelProvider(requireActivity())
            .get(SharedViewModel.class);
    }
}

Schreiben

import androidx.lifecycle.viewmodel.compose.viewModel

@Composable
fun MyScreen(
    context: Context = LocalContext.current,
    // ViewModel API available in lifecycle.lifecycle-viewmodel-compose
    // The ViewModel is scoped to the Activity of the host Fragment
    // where this composable function is called
    viewModel: SharedViewModel = viewModel(
        viewModelStoreOwner = (context as Fragment).requireActivity()
    )
) { /* ... */ }

ViewModels, die auf das Navigationsdiagramm beschränkt sind

Navigationsdiagramme sind auch Inhaber von ViewModel-Stores. Wenn Sie Navigationsfragment oder Navigation Compose verwenden, können Sie mit der navGraphViewModels(graphId)Views-Erweiterungsfunktion eine Instanz eines ViewModel abrufen, die auf ein Navigationsdiagramm beschränkt ist.

Aufrufe

import androidx.navigation.navGraphViewModels

class MyFragment : Fragment() {

    // ViewModel API available in navigation.navigation-fragment
    // The ViewModel is scoped to the `nav_graph` Navigation graph
    val viewModel: SharedViewModel by navGraphViewModels(R.id.nav_graph)

    // Equivalent navGraphViewModels code using the viewModels API
    val viewModel: SharedViewModel by viewModels(
        { findNavController().getBackStackEntry(R.id.nav_graph) }
    )
}

Aufrufe

import androidx.lifecycle.ViewModelProvider;

public class MyFragment extends Fragment {

    SharedViewModel viewModel;

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        NavController navController = NavHostFragment.findNavController(this);
        NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.my_graph);

        // The ViewModel is scoped to the `nav_graph` Navigation graph
        viewModel = new ViewModelProvider(backStackEntry).get(SharedViewModel.class);
    }
}

Schreiben

import androidx.lifecycle.viewmodel.compose.viewModel

@Composable
fun MyAppNavHost() {
    // ...
    composable("myScreen") { backStackEntry ->
        // Retrieve the NavBackStackEntry of "parentNavigationRoute"
        val parentEntry = remember(backStackEntry) {
            navController.getBackStackEntry("parentNavigationRoute")
        }
        // Get the ViewModel scoped to the `parentNavigationRoute` Nav graph
        val parentViewModel: SharedViewModel = viewModel(parentEntry)
        // ...
    }
}

Wenn Sie Hilt zusätzlich zu Jetpack Navigation verwenden, können Sie die hiltNavGraphViewModels(graphId) API so verwenden.

Aufrufe

import androidx.hilt.navigation.fragment.hiltNavGraphViewModels

class MyFragment : Fragment() {

    // ViewModel API available in hilt.hilt-navigation-fragment
    // The ViewModel is scoped to the `nav_graph` Navigation graph
    // and is provided using the Hilt-generated ViewModel factory
    val viewModel: SharedViewModel by hiltNavGraphViewModels(R.id.nav_graph)
}

Aufrufe

import androidx.hilt.navigation.HiltViewModelFactory;
import androidx.lifecycle.ViewModelProvider;

public class MyFragment extends Fragment {

    SharedViewModel viewModel;

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        NavController navController = NavHostFragment.findNavController(this);
        NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.my_graph);

        // The ViewModel is scoped to the `nav_graph` Navigation graph
        // and is provided using the Hilt-generated ViewModel factory
        viewModel = new ViewModelProvider(
            backStackEntry,
            HiltViewModelFactory.create(getContext(), backStackEntry)
        ).get(SharedViewModel.class);
    }
}

Schreiben

import androidx.hilt.navigation.compose.hiltViewModel

@Composable
fun MyAppNavHost() {
    // ...
    composable("myScreen") { backStackEntry ->
        val parentEntry = remember(backStackEntry) {
            navController.getBackStackEntry("parentNavigationRoute")
        }

        // ViewModel API available in hilt.hilt-navigation-compose
        // The ViewModel is scoped to the `parentNavigationRoute` Navigation graph
        // and is provided using the Hilt-generated ViewModel factory
        val parentViewModel: SharedViewModel = hiltViewModel(parentEntry)
        // ...
    }
}