即使没有在可组合项内部进行推送,StateFlow 状态的更改也会不断更新。
@Composable
fun ScreenController(
viewModel: SyncViewModel, log: Logger,
navigateToLogin: () -> Unit,
navigateToSync: () -> Unit,
navigateToAttendance: () -> Unit,
navigateToDashBoard: () -> Unit,
) {
val state by viewModel.userCurrentState.collectAsState()
LaunchedEffect(Unit) {
viewModel.getUserState()
}
state.let {
if (!it.isDefault) {
if (!it.isUserLoggedIn) {
navigateToLogin()
} else if (!it.isDataSyncedForToday) {
navigateToSync()
} else if (!it.isAttendanceMarked) {
navigateToAttendance()
} else {
navigateToDashBoard()
}
}
}
}
即使在启动效果中仅调用一次获取用户当前状态的方法(viewModel.getUserState()),此撰写仍会继续调用navigateToLogin方法。
下面是NavHost的代码
val navController = rememberNavController()
NavHost(navController, startDestination = FULL_SCREEN) {
composable(route = FULL_SCREEN) {
ScreenController(
syncViewModel,
log,
navigateToLogin = { navController.navigate(LOGIN_SCREEN) },
navigateToSync = { navController.navigate(DATA_SYNC) },
navigateToAttendance = { navController.navigate(ATTENDANCE_SCREEN) },
navigateToDashBoard = { navController.navigate(BASE_DASHBOARD) }
)
}
composable(route = LOGIN_SCREEN) {
LoginScreen(navController, loginViewModel, log)
}
}
因此,LoginScreen 可组合项会不断重组自身,因为状态值会发送更改事件,即使它们没有被修改。
那么,我想了解为什么状态值不断更新以及如何更新?
我尝试让状态作为生命周期感知特定的可组合项。
val lifecycleOwner = LocalLifecycleOwner.current
val lifecycleAwareLoginFlow = remember(viewModel.userCurrentState, lifecycleOwner) {
viewModel.userCurrentState.flowWithLifecycle(lifecycleOwner.lifecycle)
}
val state: UserAppState by lifecycleAwareLoginFlow.collectAsState(initial = UserAppState())
但是,状态值的变化仍在发生。
添加更多代码 -
class SyncViewModel(
private val syncRepository: SyncRepository,
log: Logger
) : ViewModel() {
private val mutableUserState: MutableStateFlow<UserAppState> =
MutableStateFlow(UserAppState())
val userCurrentState: StateFlow<UserAppState> =
mutableUserState
fun getUserState(): Job {
return viewModelScope.launch {
val isUserLoggedIn = syncRepository.isUserLoggedIn()
val isSyncDone = syncRepository.isRequiredAPIsSynced()
val isAttendanceMarked =
syncRepository.isAttendanceMarked()
log.d("App State $isUserLoggedIn, $isSyncDone,
$isAttendanceMarked")
mutableUserState.update {
it.copy(
isDefault = false,
isUserLoggedIn = isUserLoggedIn,
isDataSyncedForToday = isSyncDone,
isAttendanceMarked = isAttendanceMarked,
)
}
}
}
data class UserAppState(
val isDefault: Boolean = true,
val isUserLoggedIn: Boolean = true,
val isDataSyncedForToday: Boolean = true,
val isAttendanceMarked: Boolean = true,
)
最佳答案
由于状态值应该只被观察一次,所以我将导航逻辑移到了 Launch 效果中。
state.let {
if (!it.isDefault) {
LaunchedEffect(it) {
if (!it.isUserLoggedIn) {
navigateToLogin()
} else if (!it.isDataSyncedForToday) {
navigateToSync()
} else if (!it.isAttendanceMarked) {
navigateToAttendance()
} else {
navigateToDashBoard()
}
}
这样,状态更改就不会再次推送,这对我来说是一个解决方法,可以帮助像我这样的人,请分享正确的解决方案。
关于android - 可组合性在无限循环中不断刷新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75702596/