在为Android运行Firebase实时数据库时,我面临非常奇怪的结果。 主要问题是:
我的Firebase数据库中具有这种结构。
{
"users" : {
"-LOOlXqtc0XK3ZXLKFc6" : {
"Age" : 50,
"Name" : "Ali"
},
"-LOPIfgGQMhyMkRMcpTb" : {
"Age" : 80,
"Name" : "New Name"
}
}
}
这是我的MainActivity代码:
mDatabase = FirebaseDatabase.getInstance();
mRef = mDatabase.getReference("users");
在单击“插入数据”按钮时执行此代码。
private void runCode(View view){
String name = mInputText.getText().toString();
int age= Integer.parseInt(mInputNum.getText().toString());
String key = mRef.push().getKey();
mRef.child(key).child("Name").setValue(name);
mRef.child(key).child("Age").setValue(age);
}
这是使用valueEventListener读取数据按钮的click方法。
private void readData(View view) {
//read data here
//this read data method has value listener not child listener
mRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
Person data= dataSnapshot.getValue(Person.class);
Map<String,Object> data1= (Map<String, Object>) dataSnapshot.getValue();
Log.d(TAG, "onChildAdded: Name: "+data1.get("Name"));
Log.d(TAG, "onChildAdded: Age: "+data1.get("Age"));
Log.d(TAG, "This is Person: "+data);
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
logcat的输出是这样的: 这是我第一次单击“读取数据”方法。
D/MyTag: onChildAdded: Name: Ali
D/MyTag: onChildAdded: Age: 50
D/MyTag: This is Person: Person{Name='Ali', Age=50}
这是当我插入一个名称为“ New Name”且年龄为80的新孩子时的logcat输出。
D/MyTag: onChildAdded: Name: Ali
D/MyTag: onChildAdded: Age: 50
D/MyTag: This is Person: Person{Name='Ali', Age=50}
D/MyTag: onChildAdded: Name: New Name
D/MyTag: onChildAdded: Age: null
D/MyTag: This is Person: Person{Name='New Name', Age=0}
D/MyTag: onChildAdded: Name: Ali
D/MyTag: onChildAdded: Age: 50
D/MyTag: This is Person: Person{Name='Ali', Age=50}
D/MyTag: onChildAdded: Name: New Name
D/MyTag: onChildAdded: Age: 80
D/MyTag: This is Person: Person{Name='New Name', Age=80}
回调方法是针对每个字段分别使用的,它一次返回一个字段,但这可以使setField被调用两次,因此这就是为什么要调用它的原因。但是对于儿童听众,情况更糟。
这是具有childListener实现的读取代码方法。
private void readData(View view) {
//read data here
mRef.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
Map<String,Object> data= (Map<String, Object>) dataSnapshot.getValue();
Person p=dataSnapshot.getValue(Person.class);
Log.d(TAG, "onChildAdded: Name: "+data.get("Name"));
Log.d(TAG, "onChildAdded: Age: "+data.get("Age"));
Log.d(TAG, "onChildAdded: Person is: "+p);
}
@Override
public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
}
@Override
public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
这是我第一次单击读取数据按钮时的logcat输出:
D/MyTag: onChildAdded: Name: Ali
D/MyTag: onChildAdded: Age: 50
D/MyTag: onChildAdded: Person is: Person{Name='Ali', Age=50}
D/MyTag: onChildAdded: Name: New Name
D/MyTag: onChildAdded: Age: 80
D/MyTag: onChildAdded: Person is: Person{Name='New Name', Age=80}
这是添加名称为“ Usman”且年龄为50岁的新孩子的输出
D/MyTag: onChildAdded: Name: Usman
D/MyTag: onChildAdded: Age: null
D/MyTag: onChildAdded: Person is: Person{Name='Usman', Age=0}
这仅发生在回调中。年龄没有返回,但值已正确存储在数据库中。
请帮助。我仅连接了一个侦听器,并且在停止运行进程后始终运行该应用程序。 谢谢。
答案 0 :(得分:0)
运行此代码时:
mRef.child(key).child("Name").setValue(name);
mRef.child(key).child("Age").setValue(age);
对setValue
的每次调用都会分别发送到Firebase数据库。因此,您要对数据库执行两个独立的写操作。每个写操作都可以发送给侦听器。
要使它们作为一个写操作退出,请将这两个属性组合为一个对setValue()
的调用:
Map<String, Object> values = new HashMap<String, Object>();
map.put("Name", name);
map.put("Age", age);
mRef.child(key).setValue(values);
这将对数据库执行一次写入,最终结果相同。但这只会触发一次侦听器。
如果我们回头看您的初始代码:
mRef.child(key).child("Name").setValue(name);
mRef.child(key).child("Age").setValue(age);
第一次调用setValue将导致创建$key
,而第二次调用仅更新其下的Age
节点。在mRef
上使用子侦听器时,这意味着对setValue()
的第一次调用会触发onChildAdded
,而第二个调用会触发onChildChanged()
。