我希望在可组合项加载时只运行一次代码。因此,我使用了具有键为true的LaunchedEffect来实现这一点。
LaunchedEffect(true) {
// do API call
}
这段代码目前能够正常运行,但当屏幕方向发生变化等配置更改时会再次执行。如何避免在配置更改的情况下再次运行?
我希望在可组合项加载时只运行一次代码。因此,我使用了具有键为true的LaunchedEffect来实现这一点。
LaunchedEffect(true) {
// do API call
}
rememberSaveable
进行API调用的信息:当配置更改时,它将保持不变。var initialApiCalled by rememberSaveable { mutableStateOf(false) }
if (!initialApiCalled) {
LaunchedEffect(Unit) {
// do API call
initialApiCalled = false
}
}
LaunchedEffect
协程将被取消,您的API调用也将被取消。init
内执行API调用:class ScreenViewModel: ViewModel() {
init {
viewModelScope.launch {
// do API call
}
}
}
@Composable
fun Screen(viewModel: ScreenViewModel = viewModel()) {
}
建议像这样将视图模型作为参数传递, 官方文档。在生产代码中,您无需向此视图传递任何参数,只需像 Screen()
一样调用即可:视图模型将默认创建 viewModel()
参数。如 此答案 所示,它被移至测试/预览功能的参数。
class MyViewModel : ViewModel() {
private val uiScreenState: : MutableStateFlow<WhatEverState> =
MutableStateFlow(WhatEverIntialState).also {
loadState()
}
fun loadState(): StateFlow<WhatEverState>> {
return users
}
private fun loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
class MyFragment : Fragment {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return ComposeView(requireContext()).apply {
setContent {
StartingComposeTheme {
Box(modifier = Modifier.fillMaxSize()) {
val state by viewModel.uiScreenState.collectAsState()
when (state) {
//do something
}
}
}
}
}
}
}}
@Islam Mansour 的答案适用于将专用的 viewModel 与 UI 相关联,但我的情况是多个 UI 片段共享 ViewModel。
在我的情况下,上述答案无法解决我在用户导航到相关 UI 部分时仅调用 API 一次的问题。
因为我在 NavHost
中有多个可组合的 UI,作为 Fragment。
而我的 ViewModel
贯穿所有片段。
因此,API 应该仅在用户导航到所需片段时调用。
因此,下面的惰性属性初始化程序解决了我的问题;
val myDataList by lazy {
Log.d("test","call only once when called from UI used inside)")
loadDatatoThisList()
mutableStateListOf<MyModel>()
}
mutableStateListOf<LIST_TYPE
> 会在数据添加到其中时自动重新组合UI。
使用by lazy
修饰的变量只有在显式调用时才会被初始化一次。