今天,当我在我的 android 项目上工作时,我看到了我的应用程序的这种奇怪行为。当我单击一个图标并移动到另一个活动时,这基本上会将另一个孩子插入到第一个活动正在侦听的节点中。但令我惊讶的是,当返回时,屏幕上的所有内容都翻了一番。当我刷新视图时,它会再次变得正常。我重复了很多次,认为这可能是一个小故障。但是每次都是一样的结果。当我查看数据库时,从未创建过新的孩子。
这是我的听众代码。(doOnDataChange是一个扩展函数,我为onValueEventListener定义的)
val chats = mutableListOf<Chat>()
chatsListener = dbChatsReference.orderByChild(NODE_LAST_MESSAGE_TIME).doOnDataChange { it ->
chats.clear()
viewLifecycleOwner.lifecycleScope.launch(IO) {
// some IO work
for (ss in it.children) {
Log.d(TAG, "onDataChange: ${ss.key!!} , ${Thread.currentThread()}")
// populate chats with appropriate data
}
}
}
然后我记录了发生的事情。
2020-12-08 23:52:39.721 4114-4200/com.skb.skara D/ChatsFragment: onDataChange: cleared
2020-12-08 23:52:40.043 4114-4200/com.skb.skara D/ChatsFragment: onDataChange: cleared
2020-12-08 23:52:40.132 4114-4200/com.skb.skara D/ChatsFragment: onDataChange: j7ZmBA650WVmvd9z6BsN7UsvPlJ2VtDh2KtpeDhwXN386b580Lpr6dj2 , Thread[DefaultDispatcher-worker-2,5,main]
2020-12-08 23:52:40.133 4114-4200/com.skb.skara D/ChatsFragment: onDataChange: lIq43hHgzKfsE0zbYIeiH4dhswT2KQTXik3LjYMriCOdPoTKLNAtoVf2 , Thread[DefaultDispatcher-worker-2,5,main]
2020-12-08 23:52:40.139 4114-4200/com.skb.skara D/ChatsFragment: onDataChange: lIq43hHgzKfsE0zbYIeiH4dhswT2MWUYn8kW4MPlZvnn420XrN4p5kq2 , Thread[DefaultDispatcher-worker-2,5,main]
2020-12-08 23:52:40.140 4114-4201/com.skb.skara D/ChatsFragment: onDataChange: j7ZmBA650WVmvd9z6BsN7UsvPlJ2VtDh2KtpeDhwXN386b580Lpr6dj2 , Thread[DefaultDispatcher-worker-3,5,main]
2020-12-08 23:52:40.141 4114-4201/com.skb.skara D/ChatsFragment: onDataChange: lIq43hHgzKfsE0zbYIeiH4dhswT2KQTXik3LjYMriCOdPoTKLNAtoVf2 , Thread[DefaultDispatcher-worker-3,5,main]
2020-12-08 23:52:40.143 4114-4200/com.skb.skara D/ChatsFragment: onDataChange: lIq43hHgzKfsE0zbYIeiH4dhswT2VtDh2KtpeDhwXN386b580Lpr6dj2 , Thread[DefaultDispatcher-worker-2,5,main]
2020-12-08 23:52:40.145 4114-4201/com.skb.skara D/ChatsFragment: onDataChange: lIq43hHgzKfsE0zbYIeiH4dhswT2MWUYn8kW4MPlZvnn420XrN4p5kq2 , Thread[DefaultDispatcher-worker-3,5,main]
2020-12-08 23:52:40.146 4114-4200/com.skb.skara D/ChatsFragment: onDataChange: lIq43hHgzKfsE0zbYIeiH4dhswT2j7ZmBA650WVmvd9z6BsN7UsvPlJ2 , Thread[DefaultDispatcher-worker-2,5,main]
2020-12-08 23:52:40.148 4114-4201/com.skb.skara D/ChatsFragment: onDataChange: lIq43hHgzKfsE0zbYIeiH4dhswT2VtDh2KtpeDhwXN386b580Lpr6dj2 , Thread[DefaultDispatcher-worker-3,5,main]
2020-12-08 23:52:40.150 4114-4200/com.skb.skara D/ChatsFragment: onDataChange: -MO2_oyUjEV55HAGlzXN , Thread[DefaultDispatcher-worker-2,5,main]
2020-12-08 23:52:40.152 4114-4201/com.skb.skara D/ChatsFragment: onDataChange: lIq43hHgzKfsE0zbYIeiH4dhswT2j7ZmBA650WVmvd9z6BsN7UsvPlJ2 , Thread[DefaultDispatcher-worker-3,5,main]
2020-12-08 23:52:45.395 4114-4114/com.skb.skara D/ChatsFragment: onCreateView:
2020-12-08 23:52:45.842 4114-4200/com.skb.skara D/ChatsFragment: onDataChange: cleared
2020-12-08 23:52:46.263 4114-4200/com.skb.skara D/ChatsFragment: onDataChange: j7ZmBA650WVmvd9z6BsN7UsvPlJ2VtDh2KtpeDhwXN386b580Lpr6dj2 , Thread[DefaultDispatcher-worker-2,5,main]
2020-12-08 23:52:46.264 4114-4200/com.skb.skara D/ChatsFragment: onDataChange: lIq43hHgzKfsE0zbYIeiH4dhswT2KQTXik3LjYMriCOdPoTKLNAtoVf2 , Thread[DefaultDispatcher-worker-2,5,main]
2020-12-08 23:52:46.268 4114-4200/com.skb.skara D/ChatsFragment: onDataChange: lIq43hHgzKfsE0zbYIeiH4dhswT2MWUYn8kW4MPlZvnn420XrN4p5kq2 , Thread[DefaultDispatcher-worker-2,5,main]
2020-12-08 23:52:46.273 4114-4200/com.skb.skara D/ChatsFragment: onDataChange: lIq43hHgzKfsE0zbYIeiH4dhswT2VtDh2KtpeDhwXN386b580Lpr6dj2 , Thread[DefaultDispatcher-worker-2,5,main]
2020-12-08 23:52:46.278 4114-4200/com.skb.skara D/ChatsFragment: onDataChange: lIq43hHgzKfsE0zbYIeiH4dhswT2j7ZmBA650WVmvd9z6BsN7UsvPlJ2 , Thread[DefaultDispatcher-worker-2,5,main]
然后我记得,正如这篇博客中提到的,当您对数据库进行一些更改时,会立即触发侦听器,而无需真正等待写入完成。之后,如果写入失败,则使用旧值再次触发侦听器以使先前的触发器无效。由于我在这里使用了协程,因此聊天列表由两个线程同时更新。即使对节点进行了两次更改,并且两者之间的延迟非常短,也会发生这种情况。
那么有人可以告诉我如何克服这种竞争条件。