Interfejsy API określania zakresu modeli ViewModel Część stanowiąca część Androida Jetpack.

Zakres ma kluczowe znaczenie dla efektywnego korzystania z modeli ViewModel. Każdy model ViewModel jest ograniczony do obiektu implementującego interfejs ViewModelStoreOwner. Istnieje kilka interfejsów API, które ułatwiają zarządzanie zakresem modeli ViewModel. Ten dokument przedstawia kluczowe techniki, które warto znać.

Metoda ViewModelProvider.get() umożliwia uzyskanie instancji obiektu ViewModel o zakresie dowolnego typu ViewModelStoreOwner. Użytkownicy Kotlin mogą korzystać z różnych funkcji rozszerzeń przeznaczonych do typowych zastosowań. Wszystkie implementacje funkcji rozszerzenia Kotlin używają wbudowanego interfejsu API ViewModelProvider.

Obiekty ViewModels w zakresie najbliższego obiektu ViewModelStoreOwner

Zakres modelu ViewModel możesz określić jako aktywność, fragment lub miejsce docelowe wykresu nawigacyjnego. Funkcje rozszerzenia viewModels() udostępniane przez biblioteki aktywności, fragmentów i nawigacji oraz funkcja viewModel() w narzędziu Compose umożliwiają pobranie instancji obiektu ViewModel ograniczonego do najbliższego ViewModelStoreOwner.

Wyświetlenia

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()
}

Wyświetlenia

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);
}

Utwórz

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()
) { /* ... */ }

Obiekty ViewModels przypisane do dowolnego właściciela sklepu ViewModelStore

Funkcje ComponentActivity.viewModels() i Fragment.viewModels() w systemie Widok oraz funkcja viewModel() w sekcji Tworzenie przyjmują opcjonalny parametr ownerProducer, którego możesz użyć, aby określić, do któregoViewModelStoreOwner zakresu jest ograniczona instancja obiektu ViewModel. Poniższy przykład pokazuje, jak uzyskać instancję ViewModel ograniczony do fragmentu nadrzędnego:

Wyświetlenia

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() }
    )
}

Wyświetlenia

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);
    }
}

Utwórz

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()
    )
) { /* ... */ }

Częstym przypadkiem użycia jest model ViewModel ograniczony do aktywności z fragmentu kodu. Aby to zrobić, skorzystaj z dostępnej funkcji rozszerzenia Views (activityViewModels()). Jeśli nie używasz widoków danych ani Kotlin, możesz użyć tych samych interfejsów API co powyżej oraz przekazać prawo własności.

Wyświetlenia

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()
}

Wyświetlenia

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);
    }
}

Utwórz

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()
    )
) { /* ... */ }

Modele View dostępne do wykresu nawigacyjnego

Wykresy nawigacyjne są również właścicielami magazynów ViewModel. Jeśli korzystasz z fragmentu nawigacji lub tworzenia nawigacji, wystąpienie obiektu ViewModel ograniczone do wykresu nawigacyjnego możesz znaleźć za pomocą funkcji rozszerzenia Views navGraphViewModels(graphId).

Wyświetlenia

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) }
    )
}

Wyświetlenia

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);
    }
}

Utwórz

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)
        // ...
    }
}

Jeśli oprócz nawigacji Jetpack używasz też Hilt, możesz użyć interfejsu API hiltNavGraphViewModels(graphId) w następujący sposób.

Wyświetlenia

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)
}

Wyświetlenia

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);
    }
}

Utwórz

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)
        // ...
    }
}