Android 中的数据检索无法正常工作

问题描述 投票:0回答:1

我正在研究连续计数功能,连续计数逻辑工作正常,但上次登录日期和上次连续记录的数据未正确获取。可能的原因是什么?

viewModel中用于数据检索的函数是:

suspend fun streakDataHandler(givenType: String = "lastDate"): AppData? {
        val lastDateData: Flow<AppData?> = appDataRepository.getDataStream(givenType)
            .map { dataList ->
                dataList.firstOrNull()
            }
        val coroutineScope = CoroutineScope(Dispatchers.Main)
        var data: AppData? = null
        coroutineScope.launch {
            lastDateData.collect { appData ->
                if (appData != null) {
                    data = appData
                }
                else {
                    data = null
                }
            }
        }
        return data
    }

检索和使用可组合文件中的数据的代码是:

val currentRetrievedDate: Date = Date()
    val currentDate: String = SimpleDateFormat("dd-MM-yyyy").format(currentRetrievedDate)

    var lastDateObject: AppData? = null
    LaunchedEffect(Unit) {
        lastDateObject = streakCounterViewModel.streakDataHandler()
    }
    var lastDate: String = "00-00-0000"
    if (lastDateObject != null) {
        lastDate = lastDateObject!!.content
    }

    var currentStreakObject: AppData? = null
    LaunchedEffect(Unit) {
        currentStreakObject = streakCounterViewModel.streakDataHandler("currentStreak")
    }
    var currentStreak: String = "0"

    if (currentStreakObject != null) {
        currentStreak = currentStreakObject!!.content
    }

注意:此可组合文件不用于显示条纹,它只是计算它(并在本地数据库中更新它)并将牛排的值返回到另一个显示它的可组合文件。 我单独测试过,条纹计算逻辑存在问题。问题很可能只存在于数据检索中。

数据库有3列,第一列是自动生成的int id,第二列是字符串类型,第三列是内容,也是字符串并存储我想要检索的实际数据

完整项目位于 github 上:https://github.com/tauqirnizami/HealthEase

android kotlin android-jetpack-compose android-sqlite kotlin-coroutines
1个回答
0
投票

您遇到的问题是糟糕的架构和使用多种反模式的结果。当你清理它时,你的问题就会消失。

您的代码中有几个问题。以下内容与您当前的问题相关,因为它们表明架构不好:

  1. 不要在视图模型中公开挂起函数,这样 UI 就不需要从协程中调用它们。
  2. 不要创建新的协程作用域,而是使用已经存在的
    viewModelScope
  3. 不要在视图模型中收集流,让它处理 UI 。仅在视图模型中变换流并最终将它们公开为
    StateFlow
  4. streakDataHandler
    可能总是返回 null,因为启动的协程在返回之前无法足够快地更新
    data
  5. 计数器逻辑是业务逻辑,不属于可组合项,应该由视图模型完成。实际上,代码本身属于一个用例,视图模型应该只是调用用例(请参阅此处以了解有关用例的更多信息)。请记住:可组合项仅处理状态,并关注如何显示该状态。计算任何与 UI 不直接相关的内容(例如动画),都应该移至视图模型(甚至某个较低层)。

以下问题可能与您当前的问题无关,但仍然应该修复:

  1. 这真的是你想要的吗:

    if (appData != null) {
     data = appData
    } else {
     data = null
    }
    

    data = appData
    相同。

  2. 不要使用

    !!
    ,它会使您的应用程序崩溃。用这个代替:

    val lastDate: String = lastDateObject?.content ?: "00-00-0000"
    // ...
    val currentStreak: String = currentStreakObject?.content ?: "0"
    

修复架构问题需要进行一些重构。由于无法为您提供完美的解决方案,我只会展示这通常看起来如何:

private val givenType = MutableStateFlow("lastDate")

val appData: StateFlow<AppData?> = givenType
    .flatMapLatest(appDataRepository::getDataStream)
    .map(List<AppData>::firstOrNull)
    .map {
        // Call your use case to perform necessary calculations.
        // This could even perform database updates. 
    }
    .stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5_000),
        initialValue = null,
    )

fun updateGivenType(givenType: String) {
    this.givenType.value = givenType
}

现在,在您的可组合项中,您可以收集 appData 流。使用这个代替 LaunchedEffect:

val lastDateObject: AppData? by streakCounterViewModel.appData.collectAsStateWithLifecycle()

您应该调整此处所示的原则,以便在重构时使用它们。

© www.soinside.com 2019 - 2024. All rights reserved.