1

I am currently developing a mobile app in Android Studio. I have a collection in Firebase firestore called Leagues. When I open a fragment from the navigation drawer, the recyclerview is empty. I have two buttons at the top of the layout, both of which open an alert dialog. When I click on either of the buttons and click on the box to start entering text, the leagues magically appear in the recyclerview! Ideally I would like them to appear when the fragment is first opened. To give a bit more context I have a method which fetches the leagues from the collection in Firebase, but having debugged it I've found that this initially returns an empty list. Only when the edittext box in the alert dialog is pressed does the list fill up. Can anyone think why this might be the case?

Thanks in advance

Edit:

public class LeaguesFragment extends Fragment {

Button buttonCreateLeague;
Button buttonJoinLeague;
View view;
FirebaseFirestore firestore;
private String leagueID;
private String userID;
private String leagueName;
private String username;
TextView textViewMyLeagues;
RecyclerView recyclerView;
private List<Leagues> leaguesList;

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    view = inflater.inflate(R.layout.fragment_leagues, container, false);
    recyclerView = (RecyclerView) view.findViewById(R.id.leaguesList);
    RecyclerViewAdapter recyclerViewAdapter = new RecyclerViewAdapter(getContext(), leaguesList);
    recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    recyclerView.setAdapter(recyclerViewAdapter);

    buttonCreateLeague = (Button) view.findViewById(R.id.buttonCreateLeague);
    buttonJoinLeague = (Button) view.findViewById(R.id.buttonJoinLeague);
    textViewMyLeagues = (TextView) view.findViewById(R.id.textViewMyLeagues);
    firestore = FirebaseFirestore.getInstance();
    userID = FirebaseAuth.getInstance().getUid();

    firestore.collection("users").document(userID).get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
        @Override
        public void onComplete(@NonNull Task<DocumentSnapshot> task) {
            if(task.isSuccessful()) {
                DocumentSnapshot documentSnapshot = task.getResult();
                username = documentSnapshot.getString("name");
            }
        }
    });

    buttonCreateLeague.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            leagueID = CreateLeagueID.randomString(6);

            AlertDialog.Builder alert = new AlertDialog.Builder(getContext());

            alert.setMessage("Enter league name");

            final EditText input = new EditText(getContext());
            alert.setView(input);

            alert.setPositiveButton("Confirm", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {

                    leagueName = input.getText().toString().trim();
                    createLeague(leagueID, leagueName);
                    addUserToLeague(leagueID, username);
                    addLeagueToUser(leagueID, userID, leagueName);

                }
            });

            alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                    // Cancelled.
                }
            });

            alert.show();
        }
    });

    buttonJoinLeague.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            AlertDialog.Builder alert = new AlertDialog.Builder(getContext());

            alert.setMessage("Enter league code");

            final EditText input = new EditText(getContext());
            alert.setView(input);

            alert.setPositiveButton("Confirm", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {

                    leagueID = input.getText().toString().trim();

                    firestore.collection("leagues").document(leagueID).collection("members").document(username).get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
                        @Override
                        public void onComplete(@NonNull Task<DocumentSnapshot> task) {
                            if(task.isSuccessful()) {
                                DocumentSnapshot documentSnapshot = task.getResult();
                                if(documentSnapshot.exists()) {
                                    Toast.makeText(getActivity(), "Already part of this league", Toast.LENGTH_SHORT).show();
                                }
                                else {
                                    firestore.collection("leagues").document(leagueID).get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
                                        @Override
                                        public void onComplete(@NonNull Task<DocumentSnapshot> task) {
                                            if (task.isSuccessful()) {
                                                DocumentSnapshot documentSnapshot = task.getResult();
                                                if (documentSnapshot.exists()) {
                                                    leagueName = documentSnapshot.getString("leagueName");
                                                    addUserToLeague(leagueID, username);
                                                    addLeagueToUser(leagueID, userID, leagueName);
                                                }
                                                else {
                                                    Toast.makeText(getActivity(), "That league does not exist", Toast.LENGTH_SHORT).show();
                                                }
                                            }
                                        }
                                    });
                                }
                            }
                        }
                    });
                }
            });

            alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                    // Cancelled.
                }
            });

            alert.show();

        }
    });

    return view;
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    leaguesList = new ArrayList<>();

    firestore = FirebaseFirestore.getInstance();
    userID = FirebaseAuth.getInstance().getUid();

    firestore.collection("users").document(userID).collection("leagues").addSnapshotListener(new EventListener<QuerySnapshot>() {
        @Override
        public void onEvent(@javax.annotation.Nullable QuerySnapshot queryDocumentSnapshots, @javax.annotation.Nullable FirebaseFirestoreException e) {
            if(e != null) {
                Log.d(TAG, "Error : " + e.getMessage());
            }

            for(DocumentChange doc: queryDocumentSnapshots.getDocumentChanges()) {
                if(doc.getType() == DocumentChange.Type.ADDED) {
                    //leagueID = doc.getDocument().getString("leagueID");
                    //leagueName = doc.getDocument().getString("leagueName");
                    Leagues leagues = doc.getDocument().toObject(Leagues.class);
                    leaguesList.add(leagues);
                }
            }

        }
    });
}

2 Answers2

1

having debugged it I've found that this initially returns an empty list.

Yes, this the normal behaviour. You cannot use now something that hasn't been loaded yet. With other words, you cannot simply create the leaguesList variable as global variable and use it outside the onEvent() method because it will always be empty due the asynchronous behaviour of this method. This means that by the time you are trying to use that list outside that method, the data hasn't finished loading yet from the database and that's why is not accessible. A quick solve for this problem would be to use leaguesList list only inside the onEvent() method, otherwise I recommend you see the last part of my anwser from this post in which I have explained how it can be done using a custom callback. You can also take a look at this video for a better understanding.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
0

Maybe the problem is your leaguesList still empty when onCreateView is trigger. And when onEvent from firestore trigger you not notify data set change the adapter.