如何在可组合函数中正确创建 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
)
}
}
在 ItemDetailsScreen 中有一个 LazyColumn:
LazyColumn {
items(
items = itemsResponse.data
) { item ->
ItemCard(
item = item,
onItemClick = {
navController.navigate(ItemDetailsScreen.route + "/${item.id}")
}
)
}
}
然后在项目上单击我导航到 ItemDetailsScreen:
fun ItemDetailsScreen(
navController: NavController,
itemId: String,
viewModel: ItemDetailsViewModel = hiltViewModel()
) {
Log.d(TAG, itemId)
}
可以看出,ViewModel 对象是在构造函数中创建的。当我打开 ItemDetailsScreen 时,日志语句被触发两次。如果我评论这一行:
//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 以了解有关这些效果处理程序的更多信息。
我的 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
)
}
}
在 ItemDetailsScreen 中有一个 LazyColumn:
LazyColumn {
items(
items = itemsResponse.data
) { item ->
ItemCard(
item = item,
onItemClick = {
navController.navigate(ItemDetailsScreen.route + "/${item.id}")
}
)
}
}
然后在项目上单击我导航到 ItemDetailsScreen:
fun ItemDetailsScreen(
navController: NavController,
itemId: String,
viewModel: ItemDetailsViewModel = hiltViewModel()
) {
Log.d(TAG, itemId)
}
可以看出,ViewModel 对象是在构造函数中创建的。当我打开 ItemDetailsScreen 时,日志语句被触发两次。如果我评论这一行:
//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 以了解有关这些效果处理程序的更多信息。