Firebase值事件监听器无法工作

7
在我的应用程序中,我有一个ID,它应该从Firebase实时数据库中拉取。如果我将其下拉并且发现没有可用的ID,则将ID设置为1。我进行了调试,发现ID已经设置为1,但是在侦听器完成后,ID变为了0。我不知道为什么或者是什么原因导致了这种情况,但这是我的代码。
侦听器的代码:
userRef.child("id").

addSingleValueEventListener(new ValueEventListener() {
    @Override public void onDataChange (DataSnapshot dataSnapshot){
        try {
            String value = dataSnapshot.getValue().toString();
            id = Integer.parseInt(value);
        } catch (NullPointerException e) {
            id = 1;  //After this, id is 1
            e.printStackTrace();
        }
    }

    @Override public void onCancelled (DatabaseError databaseError){
        id = 1;
    }
}); //Now id is 0

你说的“监听器完成后,id变为0”是什么意思?你是在哪里以及如何进行检查? - Lewis McGeary
“id”和“field id”是相同的吗? - Alex Mamo
@LewisMcGeary 哎呀,上面的评论没有正确地标记你。 - Appafly
@AlexM。id 是一个整数。 - Appafly
1
@LewisMcGeary 抱歉,这是一个单值事件监听器,我已经编辑过了。 - Appafly
显示剩余2条评论
4个回答

11

这个问题让我想到两件事情,一是关于Firebase监听器,二是关于删除多余的代码。

关于Firebase监听器的一个基本事实是它们是异步的,这意味着您的代码在执行下一行之前不会等待结果。因此,请查看此骨架代码中的注释:

userRef.child("id").
addSingleValueEventListener(new ValueEventListener() {
    @Override public void onDataChange (DataSnapshot dataSnapshot){
        // code here does not get executed straight away,
        // it gets executed whenever data is received back from the remote database
    }

    @Override public void onCancelled (DatabaseError databaseError){

    }
});
// if you have a line of code here immediately after adding the listener
// the onDataChange code *won't have run*. You go straight to these lines
// of code, the onDataChange method will run whenever it's ready.

这意味着如果你想对在 onDataChange 中获取的数据进行操作,应该将代码放在 onDataChange 方法内部(或从那里调用的其他方法中,或以某种方式在数据返回后运行该代码)。
关于第二部分,一种更 Firebase 的检查 int 存在并获取值的方式是:
@Override public void onDataChange (DataSnapshot dataSnapshot){
    if (dataSnapshot.exists()) {
        id = dataSnapshot.getValue(Integer.class);
    } else {
        id = 1;
    }
}

1
谢谢,我下次可以检查一下这是否有效。我现在正在度假。 - Appafly
太棒了,玩得开心! - Lewis McGeary
@LewisMcGeary onDataChange(){...} 会在没有对远程数据库中存储的数据进行任何更改的情况下,第一次返回数据吗?您能否澄清一下?我的问题与此有关。谢谢。 - user3314337
@user3314337 是的,它会返回第一次获取到的任何内容(为了避免混淆,因为这个问题是关于“SingleValueEventListeners”的,它只会在第一次运行时更新,不会再次更新任何更改)。我会检查你的问题。 - Lewis McGeary

0

使用 "addValueEventListener" 而不是 "addListenerForSingleValueEvent" 对我有用。

ValueEventListener locListener = new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull @NotNull DataSnapshot snapshot) {
                 //do stuff here
            }

            @Override
            public void onCancelled(@NonNull @NotNull DatabaseError error) {
                Log.d(TAG, error.toString());
            }
        };
        db.addValueEventListener(locListener);

0

我曾经遇到过从Firebase实时数据库中获取对象的类似问题,正如@Lewis McGeary所写的那样,我只是让我的程序等待,直到所有数据都从数据库中检索出来。

这是我的示例代码:

BarReference = FirebaseDatabase.getInstance().getReference("Users").child(myUID);
ValueEventListener UserChangeListener = new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        me = dataSnapshot.getValue(UserDataSet.class);
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
    }
};
BarReference.addValueEventListener(UserChangeListener);
while (me == null){
   Log.w(TAG, "Waiting For The Data to Download");
   progresBar.setVisibility(View.VISIBLE);
   return;
}


希望能有所帮助!(^_^)

0
你需要使用setValue()将id = 1设置到Firebase数据库中,尝试下面的代码行,它可能会对你有帮助。
   userRef.child("id").

  addSingleValueEventListener(new ValueEventListener() {
@Override public void onDataChange (DataSnapshot dataSnapshot){
    try {
        String value = dataSnapshot.getValue().toString();
        id = Integer.parseInt(value);
    } catch (NullPointerException e) {
         // if id=0 then set id=1 using setvalue()
        // this will set value of Id =1 in firebase database 
             id=1;                 
        userRef.child("id").setValue(id);
        log.d(LOG_TAG, e.printStackTrace());
    }
}

@Override public void onCancelled (DatabaseError databaseError){
            id=1;
          userRef.child("id").setValue(id);
   }
}); 

你想要做什么,我认为你想在数据库中的id没有值时将其存储为1?是吗? - Sagar Raut
我已经在数据库中设置了ID,然后检查它是否不为空。无论如何感谢您的帮助,但我不认为这是解决方案。 - Appafly
你想要做的是如果 id 为空,则将其设置为1,我认为你应该试试。如果 id 为空,它将首先设置为1,并且当执行此 setValue() 后,侦听器将知道 id 已更改,然后您的代码片段将执行,此时 dataSnapshot 将不会抛出空指针异常。 - Sagar Raut

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接