简体   繁体   中英

Firebase getChildrenCount not working in Android app

the maxid integer variable should have the value for the getChildrenCount() from the firebase database, but it seems that the addValueEventListener is not working.

The following is my java code from Android Studio:

@IgnoreExtraProperties
public class ProfileID_Generator extends AppCompatActivity {
    public int maxid;
    private int ProfileID;
    private String value;
    private final DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("User");

    public ProfileID_Generator(){}

    public int profileID_generate(){
        ref.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                if(snapshot.exists()){
                    maxid = (int) snapshot.getChildrenCount();
                }
            }
            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                throw error.toException();
            }
        });

        ref.child(Integer.toString(maxid)).child("ProfileID").addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                if(snapshot.exists()){
                    String val = snapshot.getValue(String.class);
                    value = val;
                }
            }
            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                throw error.toException();
            }
        });

        if(maxid==0){
            ProfileID = 10001;
        }
        else{
            ProfileID = Integer.parseInt(value)+1;
        }

        return ProfileID;
    }
}

The following is the data from the realtime database from firebase:

在此处输入图像描述

All data is loaded from Firebase (and most cloud APIs) asynchronously, which changes the order in which code executes from what you may expect and be used to.

The problem is not that getChildrenCount isn't working, but that ref.child(Integer.toString(maxid)) is executed before maxid = (int) snapshot.getChildrenCount(); . It's easiest to see this if you add some logging:

Log.i("Firebase", "Start loading maxid")
ref.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot snapshot) {
        if(snapshot.exists()){
            Log.i("Firebase", "Got data for maxid")
            maxid = (int) snapshot.getChildrenCount();
        }
    }
    @Override
    public void onCancelled(@NonNull DatabaseError error) {
        throw error.toException();
    }
});

Log.i("Firebase", "Start loading ProfileID")
ref.child(Integer.toString(maxid)).child("ProfileID").addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot snapshot) {
        if(snapshot.exists()){
            String val = snapshot.getValue(String.class);
            value = val;
        }
    }
    @Override
    public void onCancelled(@NonNull DatabaseError error) {
        throw error.toException();
    }
});

When you run this code it logs:

Start loading maxId
Start loading ProfileID
Got data for maxid

This may not be the order in which you expected the output, but it is working as designed and explains perfectly why your code doesn't work: by the time you starting loading the ProfileID , the maxid isn't known yet.


The solution for this type of problem is always the same: any code that needs the data from the database has to be inside onDataChange , be called from there, or otherwise synchronized.

So the simplest fix is to move the code that loads the ProfileID into the onDataChange that sets maxid :

ref.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot snapshot) {
        if(snapshot.exists()){
            maxid = (int) snapshot.getChildrenCount();

            ref.child(Integer.toString(maxid)).child("ProfileID").addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot snapshot) {
                    if(snapshot.exists()){
                        String val = snapshot.getValue(String.class);
                        value = val;
                    }
                }
                @Override
                public void onCancelled(@NonNull DatabaseError error) {
                    throw error.toException();
                }
            });
        }
    }
    @Override
    public void onCancelled(@NonNull DatabaseError error) {
        throw error.toException();
    }
});

This is an incredibly common problem and stumbling block for developers that are new to asynchronous APIs, so I recommend reading up on some more questions about it, such as:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM