如何重新启动功能,当它操作的数据更新时
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
当前代码中的工作对性能有影响时才使用此选项。
在片段的 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
当前代码中的工作对性能有影响时才使用此选项。