【问题标题】:Proper way to collect values from flow in android and coroutines从android和协程中的流中收集值的正确方法
【发布时间】:2021-10-20 16:54:06
【问题描述】:

我是 Kotlin 协程和流程的新手。我正在使用数据存储来存储一些布尔数据,而从数据存储中读取数据的唯一方法是根据文档使用流。

我的 ViewModel 中有这段代码

fun getRestroProfileComplete(): Boolean {
        var result = false
        viewModelScope.launch {
            readRestroDetailsValue.collect { pref ->
                result = pref.restroProfileCompleted
            }
        }

       Log.d(ContentValues.TAG, "getRestroProfileComplete outside: $result")
        return result
    }

在我的片段 onCreateView 方法中,这段代码

if(restroAdminViewModel.getRestroProfileComplete()){
       
        Log.d(TAG, "Profile Completed")
        profileCompleted(true)
    }else{
        Log.d(TAG, "Profile not completed ")
        profileCompleted(false)
    }

有时我从数据存储中获取数据,有时它总是错误的。

我知道 getRestroProfileComplete 方法函数不等待启动代码块完成并给出默认的错误结果。

最好的方法是什么?

【问题讨论】:

  • 您的视图模型应该使用布尔值向视图呈现一个流(或类似的)。
  • 你已经创建了一个竞争条件,当你的函数返回时协程可能还没有完成第一个值的收集。解释和解决方法见这里:stackoverflow.com/a/68370029/506796

标签: kotlin kotlin-coroutines flow


【解决方案1】:

您正在启动一个异步协程(带有启动),然后,无需等待它完成工作,您就返回结果变量中的任何内容。有时会设置结果,有时不会设置结果,具体取决于数据存储区加载首选项所需的时间。

如果您需要在非协程上下文中使用首选项值,则必须使用runBlocking,如下所示:

fun getRestroProfileComplete(): Boolean {
        val result = runBlocking {
            readRestroDetailsValue.collect { pref ->
                pref.restroProfileCompleted
            }
        }

       Log.d(ContentValues.TAG, "getRestroProfileComplete outside: $result")
        return result
    }

但是,这根本不是一件好事!您应该公开一个流程并从片段中使用该流程,这样您就不会阻塞主线程并且您的 UI 可以对偏好更改做出反应。

fun getRestroProfileComplete(): Flow<Boolean> {
    return readRestroDetailsValue.map { pref ->
        pref.restroProfileCompleted
    }
}

然后在片段的 onCreateView 中启动协程:

viewLifecycleOwner.lifecycleScope.launchWhenStarted {
    restroAdminViewModel.getRestroProfileComplete().collect { c ->
        if(c) {
            Log.d(TAG, "Profile Completed")
            profileCompleted(true)
        } else {
            Log.d(TAG, "Profile not completed ")
            profileCompleted(false)
        }
}

(这将继续监控首选项,您可以对流程执行其他操作,例如使用.first { it } 获取第一个true 元素)

【讨论】:

    猜你喜欢
    • 2016-03-17
    • 1970-01-01
    • 2021-11-27
    • 1970-01-01
    • 2017-07-23
    • 1970-01-01
    • 1970-01-01
    • 2021-09-15
    相关资源
    最近更新 更多