2

I want to make a nested loop for a Firebase data but the results are out of order. I know that Firebase runs asynchronously but I don't know how to solve the problem. please help me in solving the issue.

The code:

public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_recommend, container, false);
    text = view.findViewById(R.id.test);
    fuser = FirebaseAuth.getInstance().getCurrentUser();

    getInfo();

    return view;
}

private void getInfo() {
    FirebaseDatabase.getInstance().getReference().child("users").addValueEventListener(new ValueEventListener() {

        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) {
            for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
                User user = dataSnapshot.getValue(User.class);
                assert user != null;
                System.out.println("user " + user.getId() + "");
                FirebaseDatabase.getInstance().getReference().child("Posts").addValueEventListener(new ValueEventListener() {
                    @Override
                    public void onDataChange(@NonNull DataSnapshot snapshot) {
                        for (DataSnapshot datasnapshot : snapshot.getChildren()) {
                            Post post = datasnapshot.getValue(Post.class);

                            System.out.println("posts " + post.getPostid() + "");

                        }
                    }

                    @Override
                    public void onCancelled(@NonNull DatabaseError error) {

                    }
                });

            }

        }

        @Override
        public void onCancelled(@NonNull DatabaseError error) {

        }
    });
}

The results:

I/System.out: user 3JErhGpZ1IYGswKZNOTJGY7mAU13
I/System.out: user AiHsIMRL4zd9YkdkMEhY0MRhHDU2
I/System.out: user EXmknYFLpqcAHcvbcIUJYSTtDdl1
I/System.out: user KV4tUuczuUbWLz3DR0gLn8STmF73
I/System.out: user Lg8eMt56NOOAXx5PAPrYrbVnE533
I/System.out: user QOMfQ4Vhk6cOniAsj2YnMnxRP8W2
I/System.out: user Tnd20qA2g6VPr9s69ziPjou8K113
I/System.out: user YsJCUD3lq2OsVknxcRqOTQNGFpP2
I/System.out: user c8QABIe3zxNIZRCCbpvkHMd138x2
I/System.out: user pBfZlyWmGrc6h4bcLLl4Re4MHe53
I/System.out: user rRHFEuawGsMoUDzrIUaycBKy5653
I/System.out: user xUWVqIoBKsaM8eq9pm1ky0YGm5R2
I/System.out: posts -MMpqMPistmQyGm-_NpM
I/System.out: posts -MNTf7Hf6Eo_uB_jTXuw
I/System.out: posts -MNTluR0nSJARQ_tosL0
I/System.out: posts -MMpqMPistmQyGm-_NpM
I/System.out: posts -MNTf7Hf6Eo_uB_jTXuw
I/System.out: posts -MNTluR0nSJARQ_tosL0
I/System.out: posts -MMpqMPistmQyGm-_NpM
I/System.out: posts -MNTf7Hf6Eo_uB_jTXuw
I/System.out: posts -MNTluR0nSJARQ_tosL0
I/System.out: posts -MMpqMPistmQyGm-_NpM
I/System.out: posts -MNTf7Hf6Eo_uB_jTXuw
I/System.out: posts -MNTluR0nSJARQ_tosL0
I/System.out: posts -MMpqMPistmQyGm-_NpM
I/System.out: posts -MNTf7Hf6Eo_uB_jTXuw
I/System.out: posts -MNTluR0nSJARQ_tosL0
posts -MMpqMPistmQyGm-_NpM
I/System.out: posts -MNTf7Hf6Eo_uB_jTXuw
I/System.out: posts -MNTluR0nSJARQ_tosL0
I/System.out: posts -MMpqMPistmQyGm-_NpM
I/System.out: posts -MNTf7Hf6Eo_uB_jTXuw
I/System.out: posts -MNTluR0nSJARQ_tosL0
I/System.out: posts -MMpqMPistmQyGm-_NpM
I/System.out: posts -MNTf7Hf6Eo_uB_jTXuw
I/System.out: posts -MNTluR0nSJARQ_tosL0
I/System.out: posts -MMpqMPistmQyGm-_NpM
I/System.out: posts -MNTf7Hf6Eo_uB_jTXuw
I/System.out: posts -MNTluR0nSJARQ_tosL0
I/System.out: posts -MMpqMPistmQyGm-_NpM
I/System.out: posts -MNTf7Hf6Eo_uB_jTXuw
I/System.out: posts -MNTluR0nSJARQ_tosL0
I/System.out: posts -MMpqMPistmQyGm-_NpM
I/System.out: posts -MNTf7Hf6Eo_uB_jTXuw
I/System.out: posts -MNTluR0nSJARQ_tosL0
I/System.out: posts -MMpqMPistmQyGm-_NpM
I/System.out: posts -MNTf7Hf6Eo_uB_jTXuw
I/System.out: posts -MNTluR0nSJARQ_tosL0

In my Firebase, I have 12 users and 3 posts so System.out.println("posts "+post.getPostid()+""); printed 36 times. I want the code to print each user with the three posts for each as nested loop works in synchronous, not to print all users and then print posts so, how to solve it?

Son Truong
  • 12,343
  • 5
  • 28
  • 54
roro roor
  • 77
  • 2
  • 8

2 Answers2

2

Using nested loops when getting data from a Firebase database does not guarantee you have a result as the order of your loops. This is happening because each onDataChange() method within your loops has its asynchronous behavior, so nesting those loops doesn't solve the order of execution.

Unfortunately, you cannot know when getting the data from the database is completed in order to call a second loop. This is happening because Firebase is a real-time database and getting data might never complete. That's why is named a Realtime Database because at any moment the database can be changed, the item can be added or deleted.

Alex Mamo
  • 112,184
  • 14
  • 139
  • 167
Usama Altaf
  • 1,036
  • 1
  • 4
  • 23
1

There is no way to delay a print statement once you've given it. So the only way to get the output in the right order is to move the print statement to when the data you want is available.

FirebaseDatabase.getInstance().getReference().child("users").addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot snapshot) {
        for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
            User user = dataSnapshot.getValue(User.class);
            assert user != null;
            FirebaseDatabase.getInstance().getReference().child("Posts").addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot snapshot) {

                    System.out.println("user "+user.getId()+"");

                    for (DataSnapshot datasnapshot : snapshot.getChildren()) {
                        Post post = datasnapshot.getValue(Post.class);
                        System.out.println("posts "+post.getPostid()+"");
                    }
                }

                @Override
                public void onCancelled(@NonNull DatabaseError error) {
                    throw error.toException(); // don't ignore errors
                }
            });
        }
    }
    @Override
    public void onCancelled(@NonNull DatabaseError error) {
        throw error.toException(); // don't ignore errors
    }
}); 
Frank van Puffelen
  • 499,950
  • 69
  • 739
  • 734
  • Thanks for your answer.It worked. but I want to ask if there is any way to use (callbacks) or (Future) to make the code synchronous? – roro roor Dec 07 '20 at 15:59
  • You can create a custom callback of course, but that's up to you. See https://stackoverflow.com/questions/50434836/getcontactsfromfirebase-method-return-an-empty-list/50435519#50435519 for an example. – Frank van Puffelen Dec 07 '20 at 16:04