当新的子节点添加到正在侦听的节点时,为什么会触发Firebase实时数据库onChildChanged?
我有2个应用程序实例在2台设备上运行。 两个设备都在使用当新的子节点添加到正在侦听的节点时,为什么会触发Firebase实时数据库onChildChanged?,firebase,flutter,dart,firebase-realtime-database,Firebase,Flutter,Dart,Firebase Realtime Database,我有2个应用程序实例在2台设备上运行。 两个设备都在使用onChildChanged方法监听相同的DB节点更改。 将新的子节点添加到侦听的节点时,onChildChanged事件仅在添加此新节点的同一设备上触发。 在第二台设备上,由于某种原因,onChildChanged事件不会触发 但是,如果我使用onchildaded方法进行监听,那么当我们正在监听的更改节点被新添加的子节点更新时,两台设备上都会正确触发此事件onchildaded 我可以接受只有在所有设备上的任何子节点实际发生更改(不是添
onChildChanged
方法监听相同的DB节点更改。
将新的子节点添加到侦听的节点时,onChildChanged
事件仅在添加此新节点的同一设备上触发。
在第二台设备上,由于某种原因,onChildChanged
事件不会触发
但是,如果我使用onchildaded
方法进行监听,那么当我们正在监听的更改节点被新添加的子节点更新时,两台设备上都会正确触发此事件onchildaded
我可以接受只有在所有设备上的任何子节点实际发生更改(不是添加新的子节点)时才会触发onChildChanged
。但是为什么只在执行新节点添加的设备上触发onChildChanged
简言之,问题是:
为什么在设备上向DB添加新的子节点时,A和B设备上都会触发onchildaded
,而onChildChanged
仅在设备A(而不是B)上触发
相关文件:
更新:
我发现ServerValue.timestamp导致了这种行为。
如果没有ServerValue.timestamp,当我们添加新的子节点并侦听父节点更改时,onChildChanged事件从未触发。
仅当我们使用ServerValue.timestamp作为新添加子节点的字段之一时,onChildChanged事件才会发生,但仅在使用服务器时间戳值添加此新子节点的设备上发生。
我理解它最有可能被触发,因为首先使用时间戳字段占位符创建新的子节点,然后在将实际时间戳写入必填字段时,服务器会更新此节点。
所以现在的问题是:如果我们使用ServerValue.timestamp,为什么所有具有此应用程序实例的设备都不能获得onChildChanged事件?
class _MyHomePageState extends State<MyHomePage> {
final String dbDataPath = 'root/chatroom0001/messages';
DatabaseReference dbRef = FirebaseDatabase.instance.reference ();
StreamSubscription <Event> _messagesChangedSubscription;
List <String> _lMessages = List <String> ();
Future <List <String>> fetchMessages (String dbDataPath) async {
List <String> lMessages = List <String> ();
final DataSnapshot dataMessages = await dbRef.child (dbDataPath).once ();
dataMessages.value.forEach ((k, v) => {
lMessages.add (v ['message'])
});
return lMessages;
}
@override
void initState () {
super.initState ();
DatabaseReference messagesRef = dbRef.child (dbDataPath);
fetchMessages (dbDataPath).then ((lMessages) {
_lMessages = lMessages;
setState (() {});
});
_messagesChangedSubscription = dbRef.child (dbDataPath).onChildChanged.listen ((event) {
fetchMessages (dbDataPath).then ((lMessages) {
_lMessages = lMessages;
setState (() {});
});
});
}
@override
void dispose () {
super.dispose ();
_messagesChangedSubscription.cancel ();
}
@override
Widget build (BuildContext context) {
return Scaffold (
body: Container (
color: Colors.red, child: ListView.builder (
itemCount: _lMessages.length,
itemBuilder: (context, i) {
return Container (padding: EdgeInsets.all (5), child: Text (_lMessages [i], style: TextStyle (fontWeight: FontWeight.bold, fontSize: 20.0)));
}
)
),
floatingActionButton: FloatingActionButton (
onPressed: () {
DatabaseReference messagesRef = dbRef.child (dbDataPath);
DatabaseReference newChatMessageRef = messagesRef.push ();
newChatMessageRef.set ({
'message': 'Hello Google!',
'date': ServerValue.timestamp
});
},
),
);
}
}
class\u MyHomePageState扩展状态{
最终字符串dbDataPath='root/chatroom0001/messages';
DatabaseReference dbRef=FirebaseDatabase.instance.reference();
StreamSubscription _messagesChangedSubscription;
List _lMessages=List();
未来获取消息(字符串dbDataPath)异步{
List-lMessages=List();
final DataSnapshot dataMessages=wait dbRef.child(dbDataPath).once();
dataMessages.value.forEach((k,v)=>{
lMessages.add(v['message'])
});
返回消息;
}
@凌驾
void initState(){
super.initState();
DatabaseReference messagesRef=dbRef.child(dbDataPath);
获取消息(dbDataPath)。然后((lMessages){
_l消息=l消息;
setState((){});
});
_messagesChangedSubscription=dbRef.child(dbDataPath).onChildChanged.listen((事件){
获取消息(dbDataPath)。然后((lMessages){
_l消息=l消息;
setState((){});
});
});
}
@凌驾
无效处置(){
super.dispose();
_messagesChangedSubscription.cancel();
}
@凌驾
小部件构建(构建上下文){
返回脚手架(
主体:容器(
颜色:Colors.red,子项:ListView.builder(
itemCount:_lMessages.length,
itemBuilder:(上下文,i){
返回容器(padding:EdgeInsets.all(5),child:Text(_lMessages[i],style:TextStyle(fontwweight:fontwweight.bold,fontSize:20.0));
}
)
),
浮动操作按钮:浮动操作按钮(
已按下:(){
DatabaseReference messagesRef=dbRef.child(dbDataPath);
DatabaseReference newChatMessageRef=messagesRef.push();
newChatMessageRef.set({
“消息”:“你好,谷歌!”,
“日期”:ServerValue.timestamp
});
},
),
);
}
}
以下是测试项目源代码:
此代码:
DatabaseReference newChatMessageRef = messagesRef.push ();
newChatMessageRef.set ({
'message': 'Hello Google!',
'date': ServerValue.timestamp
});
将在进行更改的客户端上导致两个写入事件:
onValue
事件,也可以是onchildaded
或onChildChanged
事件,具体取决于使用的侦听器类型和本地状态
因此,在进行更改的客户端上:如果使用
onValue
侦听器,您将看到两个值事件,而如果在父节点上使用onChild
侦听器,您将看到本地事件的onchilded
,然后一个onChildChanged
作为最终值。onChildChanged事件为已更改的子节点触发,在我的经验中,该事件始终按照预期的方式运行。如果您似乎没有遇到这种情况,请编辑您的问题,以显示我们中任何人都可以使用的最小代码。@FrankvanPuffelen我发现这是由ServerValue.timestamp引起的。请看我正在解释问题的这段短视频:我还用新信息更新了问题描述。@FrankvanPuffelen请使用此链接下载复制所述情况的项目源代码:谢谢你的帮助。抱歉@hellobody,但在堆栈溢出时,需要包含在问题本身中再现问题的最小代码。与外部资源的链接往往会过时,通常会导致数据过多。既然你已经发现了问题的原因,你能编辑你的问题以包含显示问题的代码吗?请注意,代码和日志输出比问题的书面描述更有可能得到答案。@FrankvanPuffelen刚刚添加了源代码。请你坐一会儿好吗