如何在可组合函数中正确创建 ViewModel 对象?

How to create a ViewModel object inside composable function correctly?

我的 MainActivity 中有这个结构:

val navController = rememberNavController()
NavHost(
    navController = navController,
    startDestination = ItemsScreen.route
) {
    composable(
        route = ItemsScreen.route
    ) {
        ItemsScreen(
            navController = navController
        )
    }
    composable(
        route = ItemDetailsScreen.route + "/{itemId}",
        arguments = mutableStateListOf(
            navArgument("itemId") {
                type = NavType.StringType
            }
        )
    ) { backStackEntry ->
        val itemId = backStackEntry.arguments?.getString("itemId") ?: ""
        ItemDetailsScreen(
            navController = navController,
            itemId = itemId
        )
    }
}

在 ItemDetailsS​​creen 中有一个 LazyColumn:

LazyColumn {
    items(
        items = itemsResponse.data
    ) { item ->
        ItemCard(
            item = item,
            onItemClick = {
                navController.navigate(ItemDetailsScreen.route + "/${item.id}")
            }
        )
    }
}

然后在项目上单击我导航到 ItemDetailsS​​creen:

fun ItemDetailsScreen(
    navController: NavController,
    itemId: String,
    viewModel: ItemDetailsViewModel = hiltViewModel()
) {
    Log.d(TAG, itemId)
}

可以看出,ViewModel 对象是在构造函数中创建的。当我打开 ItemDetailsS​​creen 时,日志语句被触发两次。如果我评论这一行:

//viewModel: ItemDetailsViewModel = hiltViewModel()

日志语句按预期工作,它只打印一次 itemId。如何使用ViewModel对象使其只触发一次日志语句?

这也是 ViewModel class:

@HiltViewModel
class ItemDetailsViewModel @Inject constructor(
    private val useCases: UseCases
): ViewModel() {
    private val _itemState = mutableStateOf<Response<Item>>(Success(Item()))
    val itemState: State<Response<Item>> = _itemState

    fun getItem(id: String) {
        viewModelScope.launch {
            useCases.getItem(id).collect { response ->
                _itemState.value = response
            }
        }
    }
}

您不必担心日志语句被打印两次。 viewModel 创建代码没有任何问题。日志语句被打印两次,因为它直接位于可组合函数内,并且可组合函数会进行大量重构(有时甚至以不可预测的方式)。如果您只想在第一次组合可组合项时执行某些操作,请将其放在 LaunchedEffect 块中。 查看 documentation 以了解有关这些效果处理程序的更多信息。