线程安全的 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
上下文,因此其中的代码将在主线程上执行,例如执行仅限于一个线程。出现竞争条件的原因是连续调用 onLoaded()
函数并不能保证协同程序的执行顺序。
如果您从一个线程连续调用 onLoaded()
,我建议删除在其中启动协程 viewModelScope.launch
。然后将保留调用顺序。在这种情况下使用 list.postValue()
。
如果你从不同的线程调用onLoaded()
并且仍然想启动一个协程你可以参考answers to this question.
尝试在不启动协程的情况下使用 @Synchronized
注释:
@Synchronized
fun onLoaded(item: String) { ... }
定义该方法的实例的监视器将防止该方法被多个线程并发执行。在这种情况下使用 list.postValue()
。
我的以下代码存在竞争条件。我尝试在列表中找到一个项目并设置其加载 属性。但是如果 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
上下文,因此其中的代码将在主线程上执行,例如执行仅限于一个线程。出现竞争条件的原因是连续调用 onLoaded()
函数并不能保证协同程序的执行顺序。
如果您从一个线程连续调用
onLoaded()
,我建议删除在其中启动协程viewModelScope.launch
。然后将保留调用顺序。在这种情况下使用list.postValue()
。如果你从不同的线程调用
onLoaded()
并且仍然想启动一个协程你可以参考answers to this question.尝试在不启动协程的情况下使用
@Synchronized
注释:@Synchronized fun onLoaded(item: String) { ... }
定义该方法的实例的监视器将防止该方法被多个线程并发执行。在这种情况下使用
list.postValue()
。