1

I am using a RecyclerView in which I get data from a Firestore database. Here's my code for the adapter. Please pay attention to the two Log.d() statements in the constructor and one in getItemCount().

public class DonorDonateAdapter extends RecyclerView.Adapter<DonorDonateAdapter.DonorDonateViewHolder> {
    public String email;
    public static CircularImageView imageView;
    public List<String> planters;
    private FirebaseFirestore database;

    public static class DonorDonateViewHolder extends RecyclerView.ViewHolder {
        public Button profileButton;
        public TextView nameTextView;
        public TextView addressTextView;
        public ImageView donateIcon;
        public ImageView messageIcon;

        DonorDonateViewHolder(View view) {
            super(view);

            profileButton = view.findViewById(R.id.profile_button);
            imageView = view.findViewById(R.id.image_view);
            nameTextView = view.findViewById(R.id.text_view_name);
            addressTextView = view.findViewById(R.id.text_view_address);
            donateIcon = view.findViewById(R.id.donate_icon);
            messageIcon = view.findViewById(R.id.message_icon);

            MainActivity.setTextSize(nameTextView);
            MainActivity.setTextSize(addressTextView);
        }
    }

    DonorDonateAdapter(String email) {
        this.email = email;
        this.database = FirebaseFirestore.getInstance();
        this.planters = new ArrayList<>();
        this.database.collection("Planters").orderBy("Trees Planted", Query.Direction.DESCENDING).get()
                .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
                    @Override
                    public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
                        for (QueryDocumentSnapshot documentSnapshot : queryDocumentSnapshots) {
                            planters.add(documentSnapshot.getId());
                            Log.d("cs50", "onSuccess() planters.size() = " + planters.size());
                        }
                    }
                }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Log.e("cs50", "Error getting planters", e);
            }
        });
        Log.d("cs50", "constructor planters.size() = " + planters.size());
    }

//    List<String> planters = MainActivity.appDatabase.plantersDao().getAllPlantersByTreesPlanted();

    @NonNull
    @Override
    public DonorDonateViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.donor_planter, parent, false);
        Log.d("cs50", "onCreate() runs");

        return new DonorDonateViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull final DonorDonateViewHolder holder, int position) {
        final String current = planters.get(position);
        Log.d("cs50", "onBind() runs");

        database.collection("Planters").document(current).get()
                .addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
                    @Override
                    public void onSuccess(DocumentSnapshot documentSnapshot) {
                        if (documentSnapshot.getString("ImageURL") != null) {
                            new DownloadImageTask(imageView).execute(documentSnapshot.getString("ImageURL"));
                        }

                        String name = documentSnapshot.getString("Name");
                        if (name.length() <= 16) {
                            holder.nameTextView.setText(name);
                        } else {
                            holder.nameTextView.setText(name.substring(0, 12) + "...");
                        }

                        String address = documentSnapshot.getString("City") + ", " + documentSnapshot.getString("Country");
                        if (address.length() <= 16) {
                            holder.addressTextView.setText(address);
                        } else {
                            holder.addressTextView.setText(address.substring(0, 12) + "...");
                        }
                    }
                }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Log.e("cs50", "Error checking if planter exists", e);
            }
        });

        holder.profileButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent profileIntent = new Intent(view.getContext(), PlanterProfileForDonorActivity.class);
                profileIntent.putExtra("email", email);
                profileIntent.putExtra("planterEmail", current);

                view.getContext().startActivity(profileIntent);
            }
        });

        holder.donateIcon.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent donateIntent = new Intent(view.getContext(), DonateActivity.class);
                donateIntent.putExtra("email", email);
                donateIntent.putExtra("planterEmail", current);
                donateIntent.putExtra("activity", "DonorDonateActivity");

                view.getContext().startActivity(donateIntent);
            }
        });

        holder.messageIcon.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent messageIntent = new Intent(view.getContext(), MessageActivity.class);
                messageIntent.putExtra("email", email);
                messageIntent.putExtra("peerEmail", current);
                messageIntent.putExtra("isArchived", false);

                view.getContext().startActivity(messageIntent);
            }
        });
    }

    @Override
    public int getItemCount() {
        Log.d("cs50", "getItemCount() planters.size() = " + planters.size());
        return planters.size();
    }
}

Here's the logcat output I get:

2020-09-21 00:12:31.216 21938-21938/com.example.treeapp D/cs50: constructor planters.size() = 0
2020-09-21 00:12:31.447 21938-21938/com.example.treeapp D/cs50: getItemCount() planters.size() = 0
2020-09-21 00:12:31.462 21938-21938/com.example.treeapp D/cs50: getItemCount() planters.size() = 0
2020-09-21 00:12:31.648 21938-21938/com.example.treeapp D/cs50: getItemCount() planters.size() = 0
2020-09-21 00:12:31.648 21938-21938/com.example.treeapp D/cs50: getItemCount() planters.size() = 0
2020-09-21 00:12:31.682 21938-21938/com.example.treeapp D/cs50: getItemCount() planters.size() = 0
2020-09-21 00:12:31.683 21938-21938/com.example.treeapp D/cs50: getItemCount() planters.size() = 0
2020-09-21 00:12:32.067 21938-21938/com.example.treeapp D/cs50: onSuccess() planters.size() = 1
2020-09-21 00:12:32.068 21938-21938/com.example.treeapp D/cs50: onSuccess() planters.size() = 2
2020-09-21 00:12:32.068 21938-21938/com.example.treeapp D/cs50: onSuccess() planters.size() = 3
2020-09-21 00:12:32.068 21938-21938/com.example.treeapp D/cs50: onSuccess() planters.size() = 4
2020-09-21 00:12:32.068 21938-21938/com.example.treeapp D/cs50: onSuccess() planters.size() = 5
2020-09-21 00:12:32.068 21938-21938/com.example.treeapp D/cs50: onSuccess() planters.size() = 6
2020-09-21 00:12:32.068 21938-21938/com.example.treeapp D/cs50: onSuccess() planters.size() = 7
2020-09-21 00:12:32.068 21938-21938/com.example.treeapp D/cs50: onSuccess() planters.size() = 8
2020-09-21 00:12:32.069 21938-21938/com.example.treeapp D/cs50: onSuccess() planters.size() = 9
2020-09-21 00:12:32.069 21938-21938/com.example.treeapp D/cs50: onSuccess() planters.size() = 10

As you can see, the the constructor finishes executing, and then getItemCount(), and finally my planters list is filled with data from Firestore. As a result, my RecyclerView remains empty. Is there a way to get the Firestore query to execute and the list to fill up before getItemCount() is called?

All I can think of is to make the list in the activity which calls the adapter and pass in the list as a parameter to the constructor for the adapter (and do a similar thing for onResume()). Is there a better way to do this? I think this is not the way things should be done. If there is no problem with doing this, please let me know.

Huzaifa
  • 482
  • 1
  • 7
  • 20
  • 1
    Yes, use [asynchronous programming](https://stackoverflow.com/questions/47847694/how-to-return-datasnapshot-value-as-a-result-of-a-method/47853774). – Alex Mamo Sep 21 '20 at 07:50
  • @AlexMamo I liked your answer, but I figured just to call `notifyDataSetChanged()` inside the `onSuccess()` method after the list is built up. I think doing this is almost the same as following your answer. – Huzaifa Sep 21 '20 at 13:55
  • Yes, that's a solution to go ahead with. – Alex Mamo Sep 21 '20 at 16:46
  • I've upvoted it. And I'm about to use it at another place in my app. Thanks. – Huzaifa Sep 21 '20 at 16:54
  • 1
    Thank you too. You're very welcome, cheers! – Alex Mamo Sep 21 '20 at 16:55

0 Answers0