如何将Firebase数据库中的子项数存储到Android Studio中的变量

时间:2018-04-07 15:11:14

标签: android firebase firebase-realtime-database

我希望将Firebase数据库中的子项数存储到Android Studio中的变量中。我试图获取Firebase中2个不同子节点下的所有节点的总数,但它返回java.lang.ArithmeticException:除以零。任何帮助将不胜感激。

private long absent, present, total, attendanceRecord;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_student_stats);

    statsResult = (TextView) findViewById(R.id.statsResult);

    ValueEventListener eventListener = new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            for (DataSnapshot ds : dataSnapshot.getChildren()) {
                String name = ds.getKey();


                String selectedClass;
                Bundle extras = getIntent().getExtras();
                if (extras == null) {
                    selectedClass = null;
                } else {
                    selectedClass = extras.getString("classSelected");
                }
                absentNumber = FirebaseDatabase.getInstance().getReference().child("Users").child(user.getUid()).child("Classes").child(selectedClass).child("AbsentStudents").child(name);
                presentNumber = FirebaseDatabase.getInstance().getReference().child("Users").child(user.getUid()).child("Classes").child(selectedClass).child("PresentStudents").child(name);


                presentNumber.addListenerForSingleValueEvent(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {
                        for (DataSnapshot snap: dataSnapshot.getChildren()) {
                            present = snap.getChildrenCount() ;
                        }
                    }
                    @Override
                    public void onCancelled(DatabaseError databaseError) {

                    }
                });

                absentNumber.addListenerForSingleValueEvent(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {
                        for (DataSnapshot snap: dataSnapshot.getChildren()) {
                            absent = snap.getChildrenCount() ;
                        }
                    }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {

                    }
                });

                total = present + absent;
                attendanceRecord = present / total;

                allStudentsList.add(name + "\t" + attendanceRecord + "%");

            }

1 个答案:

答案 0 :(得分:0)

问题是数据是从Firebase异步加载的,当您运行除法时数据尚未加载(因此total0)。要了解异步加载的工作原理,让我们在代码中添加一些简单的日志记录:

System.out.println("Before attaching listener");
presentNumber.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        System.out.println("Got data");
    }
    @Override
    public void onCancelled(DatabaseError databaseError) {
        throw databaseError.toException(); // don't ignore errors
    }
});
System.out.println("After attaching listener");

运行此代码时,您将获得:

  

在附加监听器之前

     

附加监听器后

     

获得数据

这可能不是你预期的顺序。因为从Firebase服务器获取数据需要一些时间,所以主代码会继续(并运行“After”日志)。只有从Firebase获得数据后,您的onDataChange才会被调用。

了解这一点,我希望错误更有意义:当您运行attendanceRecord = present / total时,total仍然是0,因为数据尚未加载。< / p>

处理异步加载的解决方案是重新构建您的问题。现在你的代码说:“首先加载A,然后加载B,然后用A和B做一些事情”。相反,我觉得将其框架化为有用:“首先开始加载A和B.一旦加载A和B,就用它们做点什么。”在您的代码中,这将转换为添加额外的功能:

public void checkAttendanceRecord(long present, long absent) {
  if (present >= 0 && absent >= 0) {
    total = present + absent;
    attendanceRecord = present / total;

    allStudentsList.add(name + "\t" + attendanceRecord + "%");
  }
}

然后

long present = -1;
long absent = -1;

presentNumber.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for (DataSnapshot snap: dataSnapshot.getChildren()) {
            present = snap.getChildrenCount() ;
        }
        checkAttendanceRecord(present, absent);
    }
    @Override
    public void onCancelled(DatabaseError databaseError) {
        throw databaseError.toException(); // don't ignore errors
    }
});

absentNumber.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for (DataSnapshot snap: dataSnapshot.getChildren()) {
            absent = snap.getChildrenCount() ;
        }
        checkAttendanceRecord(present, absent);
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        throw databaseError.toException(); // don't ignore errors
    }
});

请注意,我不确定onDataChange中的循环是什么,所以我按原样保留它们,并只关注代码的异步性质。

要了解有关异步数据加载的更多信息,请查看: