ViewModel Scoping APIs   Một phần của Android Jetpack.

Phạm vi là yếu tố then chốt để sử dụng ViewModel một cách hiệu quả. Mỗi ViewModel sẽ thuộc một phạm vi đối tượng triển khai giao diện ViewModelStoreOwner. Có một số API giúp bạn dễ dàng quản lý phạm vi của ViewModel. Tài liệu này nêu ra một số kỹ thuật chính mà bạn nên biết.

Phương thức ViewModelProvider.get() cho phép bạn có được thực thể của một ViewModel thuộc phạm vi của ViewModelStoreOwner bất kỳ. Người dùng Kotlin có các hàm mở rộng khác nhau dành cho trường hợp sử dụng phổ biến nhất. Về bản chất, tất cả các phương thức triển khai hàm mở rộng Kotlin đều sử dụng API ViewModelProvider.

ViewModel thuộc phạm vi của ViewModelStoreOwner gần nhất

Bạn có thể thiết lập phạm vi của ViewModel trong một Hoạt động, Mảnh hoặc đích đến của biểu đồ Điều hướng. Với các hàm mở rộng viewModels() do thư viện Hoạt động, Mảnh và Điều hướng cung cấp cũng như hàm viewModel() trong Compose, bạn có thể xem một thực thể của ViewModel thuộc phạm vi của ViewModelStoreOwner gần nhất.

Khung hiển thị

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

Thành phần hiển thị

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

Compose

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

ViewModel thuộc phạm vi của ViewModelStoreOwner bất kỳ

Hàm ComponentActivity.viewModels()Fragment.viewModels() trong hệ thống Khung hiển thị và hàm viewModel() trong Compose sẽ lấy một tham số ownerProducer (không bắt buộc) mà bạn có thể sử dụng để chỉ định ViewModelStoreOwner nào mà thực thể của ViewModel nằm trong đó. Mẫu sau đây cho biết cách lấy một thực thể của ViewModel thuộc phạm vi của mảnh mẹ:

Số lượt xem

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

Thành phần hiển thị

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

Compose

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

Vì việc lấy ViewModel thuộc phạm vi của Hoạt động từ một Mảnh là một trường hợp sử dụng phổ biến. Trong trường hợp này, hãy sử dụng hàm mở rộng Khung hiển thị activityViewModels(). Nếu không dùng Khung hiển thị và Kotlin, bạn có thể sử dụng các API tương tự như trên và chuyển đúng đối tượng sở hữu.

Khung hiển thị

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

Thành phần hiển thị

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

Compose

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

ViewModel thuộc phạm vi của biểu đồ Điều hướng

Biểu đồ điều hướng cũng là chủ sở hữu cửa hàng ViewModel. Nếu đang sử dụng Mảnh điều hướng hoặc thành phần Điều hướng trong Compose, bạn có thể nhận một thực thể của ViewModel trong phạm vi biểu đồ Điều hướng bằng hàm mở rộng Khung hiển thị navGraphViewModels(graphId).

Số lượt xem

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

Thành phần hiển thị

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

Compose

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

Nếu đang dùng Hilt cùng với thành phần Điều hướng của Jetpack, bạn có thể sử dụng API hiltNavGraphViewModels(graphId) như sau.

Số lượt xem

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

Thành phần hiển thị

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

Compose

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