【问题标题】:Firebase ValueEventListener onDataChange() not being calledFirebase ValueEventListener onDataChange() 未被调用
【发布时间】:2017-11-03 14:05:24
【问题描述】:

我已经将我的代码追踪到了崩溃的根本原因,显然这个构造函数无法更新类的变量。当我尝试从此类中获取数据时,出现空指针异常。您可以放心地假设记录已经在数据库中,它所要做的就是获取数据并将其放入类/对象中。我现在只想获取名称,因为我正在测试对象是否仍然为空。

class Saver{
    private String name;
// constructor of Saver class
public Saver(final String uid) {
        Log.d("Saver.java","Reached here"); // this works
        FirebaseDatabase.getInstance().getReference().addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(final DataSnapshot dataSnapshot) {
                Log.d("Saver.java", "OnDataChange"); // does not work
                if(dataSnapshot.hasChild("users/" + uid)){
                    LoadRecord(dataSnapshot, uid);
                }
                else{
                    // set a new record into the database
                    FirebaseDatabase.getInstance().getReference().child("users/" + uid).setValue(CreateNewRecord(FirebaseAuth.getInstance().getCurrentUser())).addOnCompleteListener(new OnCompleteListener<Void>() {
                        @Override
                        public void onComplete(@NonNull Task<Void> task) {
                            if(task.isSuccessful()){
                                LoadRecord(dataSnapshot, uid);
                            }
                            else{
                                Log.e("Saver.java","Failed to set record in database");
                            }
                        }
                    });
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                  Log.e("LifeSaver.java","Error: " + databaseError.getMessage());
            }
        });
    }

// This function loads the data into the object
private void LoadRecord(DataSnapshot dataSnapshot, String uid){
        Log.d("LifeSaver.java","Uid:"+uid);
        // load the existing record in the database
        Saver temp = dataSnapshot.child("users/" + uid).getValue(Saver.class);
        setName(temp.getName());
    }
}
public void setName(String name) {
    this.name = name;
}
private Saver CreateNewRecord(FirebaseUser firebaseUser){
    Saver saver = new Saver ();
    saver.setName(firebaseUser.getDisplayName());
    Log.d("saver","saver name: " + saver.getName());
    return continuLifeUser;
}

显然,onDataChange 函数在数据库发生更改之前不会运行。

  1. 如果可能,如何手动触发此功能?
  2. 我应该有一个DataSnapshot 有这个节点的孩子吗?如果是这样,怎么做? (请显示代码,以便我可以直观地看到您在解释什么)
  3. 有更好的方法吗?

编辑 1: 以下是应该调用 FirebaseDatabase 的构造函数中的 logcat 语句:

D/Saver.java: Reached here with hA4hZrBieISwMOZaMYe7m6K5tpI3
I/DynamiteModule: Considering local module com.google.android.gms.firebase_database:4 and remote module com.google.android.gms.firebase_database:6
I/DynamiteModule: Selected remote version of com.google.android.gms.firebase_database, version >= 6
I/art: DexFile_isDexOptNeeded failed to open oat file '/data/dalvik-cache/x86_64/data@data@com.google.android.gms@app_chimera@m@00000004@DynamiteModulesC_GmsCore_prodlmp_alldpi_release.apk@classes.dex' for file location '/data/data/com.google.android.gms/app_chimera/m/00000004/DynamiteModulesC_GmsCore_prodlmp_alldpi_release.apk': Failed to open oat filename for reading: No such file or directory
D/Saver.java: Ended here
D/LoginAct.java: Name: null

【问题讨论】:

  • 请添加您的数据库结构并告诉我们您要获取哪些数据。
  • @AlexMamo 添加了我的数据库结构。似乎是 ValueEventListener 在调用函数时没有运行。我该如何解决这个问题?

标签: java android firebase-realtime-database


【解决方案1】:

要获取users节点下所有用户的所有名字,请使用以下代码:

DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference usersRef = rootRef.child("users");
ValueEventListener eventListener = new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for(DataSnapshot ds : dataSnapshot.getChildren()) {
            String name = ds.child("name").getValue(String.class);
            Log.d("TAG", name);
        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
};
usersRef.addListenerForSingleValueEvent(eventListener);

输出将是:

Michael Ong
//other names

如果您只想获取特定用户的姓名,请使用以下代码:

FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
String uid = firebaseUser.getUid();

DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference uidRef = rootRef.child("users").child(uid);
ValueEventListener eventListener = new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        String name = dataSnapshot.child("name").getValue(String.class);
        Log.d("TAG", name);
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
};
uidRef.addListenerForSingleValueEvent(eventListener);

输出将只有一条记录:

Michael Ong

【讨论】:

  • 此代码与我的版本有些相同,只是我的版本有dataSnapshot.hasChild("users/" + uid)。我尝试了你的代码,但监听器再次没有运行。
  • 您是否在 Firebase 控制台中将权限更改为 true?你的 logcat 有错误吗?
  • 如果您指的是规则,我已将.read.write 设置为auth !=null。关于错误,我已经用我的构造函数的开始调试语句和我的构造函数的结束调试语句更新了问题。
  • 可以分享你的 build.gradle 文件吗?您的 Google Play 服务似乎有错误。
  • 添加了两个build.gradle 文件
【解决方案2】:

我通过加载屏幕解决了这个问题。我应该记得调用是异步的,它需要一个接收器来调用将放置数据的函数,然后再继续下一个活动。

private interface OnGetDataListener {
    void onSuccess(DataSnapshot dataSnapshot);
    void onFailure();
}

这是一个监听器的小代码,当您调用数据库来获取数据时,您必须实现它。您可以查看与此类似的其他帖子。

【讨论】:

    【解决方案3】:

    您好,首先您应该将数据添加到数据库中,然后才会起作用。 Firebase 中好像没有可用的数据。只需在 firebase 数据库中添加一个键值对即可触发。

    FirebaseDatabase.getInstance().getReference().child("users/" + uid).addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(final DataSnapshot dataSnapshot) {
                Log.d("Saver.java", "OnDataChange"); // does not work
                if(dataSnapshot!=null){
                    LoadRecord(dataSnapshot);
                }
                else{
                    // set a new record into the database
                    FirebaseDatabase.getInstance().getReference().child("users/" + uid).setValue(CreateNewRecord(FirebaseAuth.getInstance().getCurrentUser())).addOnCompleteListener(new OnCompleteListener<Void>() {
                        @Override
                        public void onComplete(@NonNull Task<Void> task) {
                            if(task.isSuccessful()){
                                LoadRecord(dataSnapshot);
                            }
                            else{
                                Log.e("Saver.java","Failed to set record in database");
                            }
                        }
                    });
                }
            }
    
            @Override
            public void onCancelled(DatabaseError databaseError) {
                  Log.e("LifeSaver.java","Error: " + databaseError.getMessage());
            }
        });
    }
       // Load record should be like this...
       private void LoadRecord(DataSnapshot dataSnapshot){
        Log.d("LifeSaver.java","Uid:"+uid);
        // load the existing record in the database
        Saver temp = dataSnapshot.getValue(Saver.class);
        setName(temp.getName());
    }
    

    }

    【讨论】:

    • 就像我说的,假设数据库中有数据是安全的。因为数据库上有数据,我可以看到那里有数据。我只需要找回它。
    • 不要放在构造函数中,单独尝试。如果有数据,那么它应该可以工作。
    • 并为 /users 添加监听器,以便在添加新用户时调用它。
    • 将它放在另一个函数上,但当我尝试记录名称时它仍然打印出空指针异常
    • 我对查询进行了更改,您可以使用这样的方式来检查...如果用户不在那里,它将返回 null ,然后创建新用户。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-06
    • 1970-01-01
    • 1970-01-01
    • 2021-07-29
    • 2020-04-21
    相关资源
    最近更新 更多