繁体   English   中英

线程安全的 LiveData 更新

[英]Thread safe LiveData updates

我有以下具有竞争条件的代码。 我尝试在列表中找到一个项目并设置其加载属性。 但是如果从不同的线程多次调用onLoaded("A")onLoaded("B") 如果在第二次开始之前没有完成,我总是会丢失第一次调用的数据。

我怎样才能使这项工作? 使用 Mutex 应该是正确的方法吗?

val list = MutableLiveData<List<Model>>() // assume this is initialized with ["Model(false, "A"), Model(false, "B")]

data class Model(
    val loaded: Boolean,
    val item: String,
)

fun onLoaded(item: String) = viewModelScope.launch {
    val currList = list.value ?: return@launch

    withContext(Dispatchers.Default) {
        val updated = currList.find { it.item == item }?.copy(loaded = true)
        val mutable = currList.toMutableList()
        updated?.let {
            val index = mutable.indexOf(it)
            mutable[index] = it
        }
        list.postValue(mutable.toList())
    }
}

onLoaded("A")
onLoaded("B")

expected: ["Model(true, "A"), Model(true, "B")]
actual: ["Model(false, "A"), Model(true, "B")]

onLoaded()中,使用viewModelScope启动了一个新的协程。 viewModelScope具有Dispatchers.Main.immediate上下文,因此其中的代码将在主线程上执行,例如执行仅限于一个线程。 之所以有 Race Condition,是因为连续调用onLoaded()函数并不能保证协程执行的顺序。

  • 如果您从一个线程连续调用onLoaded() ,我建议删除在其中启动协程viewModelScope.launch 然后将保留调用顺序。 在这种情况下使用list.postValue()

  • 如果您从不同的线程调用onLoaded()并且仍想启动协程,您可以参考这个问题的答案

  • 尝试在不启动协程的情况下使用@Synchronized注释:

     @Synchronized fun onLoaded(item: String) { ... }

    定义方法的实例的监视器将保护方法免受多个线程的并发执行。 在这种情况下使用list.postValue()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM