android - 可组合性在无限循环中不断刷新

标签 android android-jetpack-compose kotlin-flow

即使没有在可组合项内部进行推送,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/

相关文章:

android - Kotlin Map 项目列表流

android - 如何在 Jetpack Compose 中对齐底部一行?

android - Jetpack Compose 使用 Painter 在图像上绘图

android - Jetpack 撰写内部编译器参数警告

android - 如何从 Paging 3 测试 PagingData

Kotlin 从 generateSequence() 到 flow() ,但生成了错误的字节码

android - 在 Android SDK 中找不到 usb_driver 文件夹

java - 我如何每次都创建一个新文件,这样什么都不会被覆盖?

java - Android 从 ArrayList<List<String>> 中删除项目

android - 大型 Android 项目的良好项目结构示例