1

I want to store my database child in an array list of my model.

Model:

public class testInformation {
private String taskName;
private String answer;

public testInformation() {
}

public String getTaskName() {
    return taskName;
}

public void setTaskName(String taskName) {
    this.taskName = taskName;
}

public String getAnswer() {
    return answer;
}

public void setAnswer(String answer) {
    this.answer = answer;
}
}

In the fragment's onCreate() method, I call a GetDataFromDatabase() method, which looks like this:

public void GetDataFromDatabase(){
    mFirebaseDatabase= FirebaseDatabase.getInstance();
    myref=mFirebaseDatabase.getReference().child("solutionKey");
    myref.keepSynced(true);
    myref.addListenerForSingleValueEvent(new ValueEventListener() {

        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            for (DataSnapshot ds:dataSnapshot.getChildren()){
                testInformation testInformation=new testInformation();
                testInformation.setTaskName(ds.getKey().toString());
                testInformation.setAnswer(ds.getValue().toString());
                results.add(testInformation);
            }
        }
        @Override
        public void onCancelled(DatabaseError databaseError) {
        }
    });
}

I have a public ArrayList<testInformation> variable called results, which is used to store the data from the database, but even after the GetDataFromDatabase() is called, the results list seems to be empty, but when i put a breakpoint at the OnDataChange() method, it seems to get filled up with the proper data.

My question is, how can I get the filled up results list from the OnDataChange() to work with it?

Edit: This list won't be modified or changed, so I only need to get it once, that's why I used the addListenerForSingleValueEvent() method.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
kac5a
  • 31
  • 1
  • 4
  • 1
    Likely, you're reading from the ArrayList before it is populated with data. I could try to help if you post the code where you're reading from the list. – Simp Slayer Apr 10 '18 at 15:48
  • what are you using results for? – Levi Moreira Apr 10 '18 at 16:45
  • It's a list of testInformation objects that contain the data pulled from the Firebase database. – kac5a Apr 10 '18 at 16:54
  • 1
    Where are you using the list? The probable issue is that you're expecting the results list to be filled when GetDataFromDatabase function returns, which is not necessarily true. The event listener is called asynchronously. If you would post more code, I'd be able to help. – Simp Slayer Apr 10 '18 at 17:07
  • Possible duplicate of [How to return dataSnapshot value as a result of a method?](https://stackoverflow.com/questions/47847694/how-to-return-datasnapshot-value-as-a-result-of-a-method) – Alex Mamo Apr 23 '18 at 17:27
  • Please check the duplicate to see why is this happening and how you can solve it. – Alex Mamo Apr 23 '18 at 17:28

2 Answers2

0

This is how the code is structured:

public class EndOfTestFragment extends Fragment {


    private FirebaseDatabase mFirebaseDatabase;
    private DatabaseReference myref;
public ArrayList<testInformation> results;

...

@Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
...
GetDataFromDatabase();
...
}
public void GetDataFromDatabase(){
        mFirebaseDatabase= FirebaseDatabase.getInstance();
        myref=mFirebaseDatabase.getReference().child("solutionKey");
        myref.keepSynced(true);
        myref.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                for (DataSnapshot ds:dataSnapshot.getChildren()){
                    testInformation testInformation=new testInformation();
                    testInformation.setTaskName(ds.getKey().toString());
                    testInformation.setAnswer(ds.getValue().toString());
                    results.add(testInformation);
                }
            }
            @Override
            public void onCancelled(DatabaseError databaseError) {
            }
        });
    }
kac5a
  • 31
  • 1
  • 4
  • 1
    What do you want to do with the data? display it? – Nirel Apr 10 '18 at 18:19
  • This is an IQ test, and I want to give the solution key stored in the Firebase database to an evaluation class to process the correct answers of the user. – kac5a Apr 11 '18 at 06:45
0
public class EndOfTestFragment extends Fragment {
private FirebaseDatabase mFirebaseDatabase;
private DatabaseReference myref;
public ArrayList<testInformation> results;

//...

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    //...
    GetDataFromDatabase();// This returns before results.add(...) is called
    // Whatever code is after this line gets run before results list has data
    /* LABEL#1 */
    // The results list is probably NOT populated yet so don't use it here
}
public void GetDataFromDatabase() {
    mFirebaseDatabase= FirebaseDatabase.getInstance();
    myref=mFirebaseDatabase.getReference().child("solutionKey");
    myref.keepSynced(true);

    myref.addListenerForSingleValueEvent(new ValueEventListener() {// This function returns immediately, does not wait for data from Firebase...
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            /* LABEL#2 */
            for (DataSnapshot ds:dataSnapshot.getChildren()){
                testInformation testInformation=new testInformation();
                testInformation.setTaskName(ds.getKey().toString());
                testInformation.setAnswer(ds.getValue().toString());
                results.add(testInformation);
            }
            // The results list is populated now, do whatever you want with it here
        }
        @Override
        public void onCancelled(DatabaseError databaseError) {
        }
    });
}

Code in LABEL#1 executes before LABEL#2

The onDataChange(...) function gets called in the background whenever the data is available.
addListenerForSingleValueEvent() does not wait for data and returns immediately.

Simp Slayer
  • 132
  • 1
  • 10
  • I kind of figured this out. The activity has 3 fragments, EndOfTestFragment is called last. When I run in debug mode, and put a break point at the onDataChange(), it breaks at the start of the second fragment and processes the method. If I'd create an ArrayList in the activity, and I'd fill that ArrayList in the OnDataChange(), would I be able to work with that list in the EndOfTestFragment fragment? – kac5a Apr 11 '18 at 08:40
  • Is the onDataChange() in your second fragment? – Simp Slayer Apr 11 '18 at 12:04
  • It's in the third one. I kind of solved this problem by removing the data whole GetDataFromDatabase() to the activity's onCreate(), and adding the vaules to a static ArrayList(), then accessing that from the third fragment to process it, but the problem is that before I call the fragment into the activity, the evaluation method runs. It should get two arraylists, but the second one is empty at that point. – kac5a Apr 11 '18 at 19:17
  • You'll have to post the code you're talking about so I can help further. All I can tell you at this point without the code is that anything you want to do with the ArrayList should happen inside the onDataChange() method. – Simp Slayer Apr 12 '18 at 07:56