Jetpack Compose 返回页面时如何重新调用ViewModel中的API更新数据
实现方案
问题根因
- ViewModel的
init代码块仅会在ViewModel实例第一次创建时执行一次,只要ViewModel绑定的宿主(如Activity、导航回栈条目)未销毁,导航返回时ViewModel不会重建,因此不会重新触发接口请求。
实现方案
我们可以通过在Compose页面监听生命周期可见事件,每次页面回到前台时主动触发接口调用:
第一步:修改Compose页面代码
在你的页面代码最上方添加如下生命周期监听逻辑:
import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.rememberUpdatedState // 你的页面Composable函数 @Composable fun ProfilePage(viewModel: ProfileViewModel = hiltViewModel()) { val lifecycleOwner = LocalLifecycleOwner.current val currentVm = rememberUpdatedState(newValue = viewModel) // 监听页面生命周期 DisposableEffect(lifecycleOwner) { val observer = LifecycleEventObserver { _, event -> // 页面回到前台可见时触发接口请求 if (event == Lifecycle.Event.ON_RESUME) { currentVm.value.clientInfoOnEvent() } } lifecycleOwner.lifecycle.addObserver(observer) onDispose { lifecycleOwner.lifecycle.removeObserver(observer) } } // 保留你原来的页面代码 val state = viewModel.state.value Column( modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.Start ) { // 原有逻辑不变 state.info?.apply { Text( text = "$givenName $lastName", style = AppFont.PoppinsTypography.button, color = AppColor.neutralColor.CHARCOAL, modifier = Modifier.padding(top = 4.dp, bottom = 4.dp) ) val clientData = let { it.copy(currency = Currency().copy(signSvg = it.currency?.signSvg.urlEncoder())) } TextIcon( text = stringResource(R.string.edit_profile), icon = painterResource(id = R.drawable.ic_right), color = AppColor.neutralColor.SPANISH_GRAY, style = AppFont.PoppinsTypography.caption, onCLick = { state.info?.let { viewModel.navigate( EditProfileDestination.createEditProfileRoute( Gson().toJson(clientData) ) ) } }) } } }
第二步:可选优化
- 避免重复请求:你可以去掉ViewModel
init块中的clientInfoOnEvent()调用,改为完全由生命周期ON_RESUME触发,第一次打开页面时也会自动调用,不会出现首次无数据的问题。 - 添加防抖逻辑:避免短时间内多次切页导致重复请求,同时修复原有代码未重置加载状态的问题,修改ViewModel代码:
@HiltViewModel class ProfileViewModel @Inject constructor( private val profileUseCases: ProfileUseCases, private val clientNavigator: ClientNavigator, private val isLoggedInDataStore: IsLoggedInDataStore ) : ViewModel(), ClientNavigator by clientNavigator { private val _state = mutableStateOf(ProfileState()) val state: State<ProfileState> = _state // 记录上次请求时间,用于防抖 private var lastRequestTime = 0L // 可删除init块的调用,完全由生命周期触发 // init { // clientInfoOnEvent() // } fun clientInfoOnEvent() { // 1秒内只允许触发一次请求 val currentTime = System.currentTimeMillis() if (currentTime - lastRequestTime < 1000) return lastRequestTime = currentTime profileUseCases.getClientInfoUseCase().onEach { result -> when (result) { is Resource.Success -> { _state.value = state.value.copy( info = result.data, isLoading = false // 重置加载状态 ) } is Resource.Error -> { _state.value = state.value.copy( error = result.message ?: "An unexpected error occurred", isLoading = false // 重置加载状态 ) } is Resource.Loading -> { _state.value = state.value.copy(isLoading = true) } } }.launchIn(viewModelScope) } }
内容的提问来源于stack exchange,提问作者Saeed Noshadi
相关产品推荐
相关产品推荐

