与 LiveData 竞争条件

时间:2021-03-28 01:34:04

标签: android kotlin synchronization android-livedata

TL;此问题的DR:

<块引用>

是否有可能将用于 const wait = ms => new Promise(resolve => setTimeout(resolve, ms)) ; const watch = async (predicate, ms) => { for (;; await wait(ms)) { const result = await predicate(); if (result) { return result; } } }; /* mock the API for demonstration purposes */ const checkOrderStatus = (() => { let calls = 0; return async () => ({ status: ++calls === 3 ? "FILLED" : false }); })(); const watchFill = (asset, orderId) => watch(async () => { const {status} = await checkOrderStatus(); console.log(`Order status: ${status}`); return status === "CANCELLED" ? false : status === "FILLED"; }, 1000) ; const sellOrder = async () => { try { const orderIsFilled = await watchFill(); console.log("orderIsFilled:", orderIsFilled); } catch (err) { console.error('Err sellIfFilled() :', err); } }; sellOrder();LiveData 的 ViewModel 中带有 backing property (MutableLiveData)Observe ArrayList 可以有竞争条件,需要使用 Add 还是 Synchronized? 假设 ArrayList 将从回调中获取其值

我正在尝试使用 Agora Android SDK 设置群组视频通话。我遵循了文档 here。问题出在 IRtcEngineEventHandler 中的 Lock

<块引用>

OnUserJoined 回调

callbacks (onUserJoined, onUserOffline)
<块引用>

onUserOffline 回调

mRtcEngine = RtcEngine.create(baseContext, APP_ID, object : IRtcEngineEventHandler() {
override fun onUserJoined(uid: Int, elapsed: Int) {
    // onUserJoined callback is called anytime a new remote user joins the channel
    super.onUserJoined(uid, elapsed)

    // We mute the stream by default so that it doesn't consume unnecessary bandwidth
    mRtcEngine?.muteRemoteVideoStream(uid, true)

    // We are using a lock since uidList is shared and there can be race conditions
    lock.lock()
    try {
        // We are using uidList to keep track of the UIDs of the remote users
        uidList.add(uid)
    } finally {
        lock.unlock()
    }

此处使用 override fun onUserOffline(uid: Int, reason: Int) { // onUserOffline is called whenever a remote user leaves the channel super.onUserOffline(uid, reason) // We use toRemove to inform the RecyclerView of the index of item we are removing val toRemove: Int // We are using a lock since uidList is shared and there can be race conditions lock.lock() try { // We are fetching the index of the item we are about to remove and then remove the item toRemove = uidList.indexOf(uid) uidList.remove(uid) } finally { lock.unlock() } Lock 方式访问 uidlist 以防止 thread safe。当我完全遵循文档时,它对我有用,但是当我尝试在 race condition 中使用带有 LiveDatabacking property (MutableLiveData) 来保存 ViewModel 时,观察者在uidlist 总是返回一个空列表。

<块引用>

我的视图模型

uidlist

}

我在 class MainViewModel: ViewModel() { private val _uidList: MutableLiveData<ArrayList<Int>> = MutableLiveData() val uidList: LiveData<ArrayList<Int>> get() = _uidList init { _uidList.value = ArrayList<Int>() } fun addToUserList(uid: Int) { _uidList.value?.add(uid) Log.d("adding user ","$uid") } fun removeFromUserList(uid: Int) { _uidList.value?.remove(_uidList.value!!.indexOf(uid)) } 内调用 addToUserList(),在 onUserJoined()} 内调用 removeFromUserList()

请指导我解决这个问题,

谢谢

1 个答案:

答案 0 :(得分:2)

你不应该改变存储在 LiveData 中的值,你会得到非常奇怪的行为。您必须完全换出该值。

我有点懒惰,所以我只是给你答案。

class MainViewModel: ViewModel() {
private val _uidList: MutableLiveData<List<Int>> = MutableLiveData()
val uidList: LiveData<List<Int>> get() = _uidList

init {
    _uidList.value = emptyList<Int>()
}

fun addToUserList(uid: Int) {
    _uidList.value = (_uidList.value ?: emptyList()) + uid
    Log.d("adding user ","$uid")
}

fun removeFromUserList(uid: Int) {
    val value = _uidList.value?.toMutableList()
    if (value == null) return
    value.remove(value.indexOf(uid))
    _uidList.value = value
}