如何重新启动功能,当它操作的数据更新时

How to restart a function, when the data it operating on it is updated

在片段的 onCreateView() 方法中,我将 3 valueEventListener 附加到 firebase 数据库中不同的、互斥的位置。每当引用处的数据更新时,它们都会被异步触发。我的示例代码如下所示:

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    listner1 = ref1.addCustomValueEventListener {
        list1.clear()
        // do some operation and populate list1
        rewriteMainData()
    }
    listner2 = ref2.addCustomValueEventListener {
        list2.clear()
        // do some operation and populate list2
        rewriteMainData()
    }
    listner3 = ref3.addCustomValueEventListener {
        list3.clear()
        // do some operation and populate list3
        rewriteMainData()
    }
}

private fun rewriteMainData() {
    mainList.clear()
    mainDbReference.addCustomListenerForSingleValueEvent {
        // compare the values present here with values in list1, list2, list3
        // populate mainList with appropriate values
        // notifyAdapterDataSetChanged
    }
    return
}

// EXTENSION FUNCTION
internal inline fun DatabaseReference.addCustomValueEventListener(crossinline onDataChange: (DataSnapshot) -> Unit) =
addValueEventListener(object : ValueEventListener {
    override fun onDataChange(snapshot: DataSnapshot) {
        onDataChange(snapshot)
    }
    override fun onCancelled(error: DatabaseError) {
        Log.e(TAG, "onCancelled: ", error.toException())
    }
})

然而,在此示例中,如果一个侦听器紧接着另一个侦听器被触发,则 rewriteMainData() 将被调用两次。届时,mainList会被两个回调同时写入。解决这个问题的一种方法是使用 ReentrantLock 的实例来避免同时写入。但这使得最新的调用要等到它之前的调用完成,这是多余的,因为所有数据都将被清除和重写。
因此,有什么方法可以知道 rewriteMainData() 何时被调用,如果它已经是 运行,那么只需中止并使用更新的列表重新启动函数?

mainList will be wrote simultaneously by two callbacks.

使用此处的代码无法做到这一点。默认情况下,数据库回调在 Android 主线程上调用,这意味着它们不能同时调用。它们将被顺序调用。因此,您不必担心线程或锁定。

您可以yield,每次在进行任何密集工作之前检查当前协程是否被取消。

// instance variable on the class
var job1: Job? = null

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    ref1.addCustomValueEventListener {
        job1?.cancel()
        job2?.cancel()
        job3?.cancel()

        job1 = lifecycleScope.launch(Dispatchers.Default) {
            list1.clear()
    
            // do some operation and populate list1
            rewriteMainData()
        }
    }
    // ...
}


private suspend fun rewriteMainData() {
    mainList.clear()

    // before every intensive work, to check for cancellation.
    yield()
    // some work involving cpu consumption or takes significant time.
}

请注意,如果工作只是同步更新列表,则影响很小,甚至更糟,这只涉及几个 CPU 周期和毫秒的时间。仅当您确定 rewriteMainData 当前代码中的工作对性能有影响时才使用此选项。