Haziq Mt Roslan
Haziq Mt Roslan

Reputation: 25

How to getItemCount() when using FirestoreRecyclerAdapter because it always return 0?

I'm currently building a booking application for laundry's machine. I need to get the item count and if the count is zero it will show the dialog box which told user that there is no data in the system.

The Activity code:

public class DobbySelection2 extends AppCompatActivity {
    String local;
    private Dialog dialog;
    private FirebaseFirestore db = FirebaseFirestore.getInstance();

    private DobbyAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dobby_selection2);

        dialog = new Dialog(this);
        dialog.setContentView(R.layout.custom_dialog2);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            dialog.getWindow().setBackgroundDrawable(getDrawable(R.drawable.custom_dialogbackground));
        }
        dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        dialog.setCancelable(false); //Optional
        dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation; //Setting the animations to dialog

        Button Yes = dialog.findViewById(R.id.btn_yes);
        Yes.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(DobbySelection2.this, MainActivity.class );
                dialog.dismiss();
                startActivity(intent);
            }
        });

        setUpRecyclerView();
    }

    private void setUpRecyclerView(){
        Intent i = getIntent();
        local = i.getStringExtra("PLACE");

        if (local == null){
            local = "Selangor";
        }

        CollectionReference dobbyRef = db.collection("locality")
                .document(local)
                .collection("Dobby");

        Query query = dobbyRef.orderBy("name", Query.Direction.DESCENDING);

        FirestoreRecyclerOptions<Dobby> options = new FirestoreRecyclerOptions.Builder<Dobby>()
                .setQuery(query, Dobby.class)
                .build();

        adapter = new DobbyAdapter(options);

        RecyclerView recyclerView = findViewById(R.id.recycler_view);
        recyclerView.setHasFixedSize(true);
        //recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setLayoutManager(new CustomLinearLayoutManager(this));
        recyclerView.setAdapter(adapter);

        if(adapter.getItemCount() == 0){
            dialog.show();
        }


        adapter.setOnItemClickListener(new DobbyAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(DocumentSnapshot documentSnapshot, int position) {
                Dobby dobby = documentSnapshot.toObject(Dobby.class);
                String id = documentSnapshot.getId();
                Toast.makeText(DobbySelection2.this, "ID : " + id, Toast.LENGTH_SHORT).show();
                Intent intent = new Intent(DobbySelection2.this, Booking2.class);
                intent.putExtra("PLACE", local);
                intent.putExtra("ID", id);
                startActivity(intent);
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        adapter.startListening();
    }

    @Override
    protected void onStop() {
        super.onStop();
        adapter.stopListening();
    }
}

Adapter code:

public class DobbyAdapter extends FirestoreRecyclerAdapter<Dobby, DobbyAdapter.DobbyHolder>{

    private OnItemClickListener listener;
    /**
     * Create a new RecyclerView adapter that listens to a Firestore Query.  See {@link
     * FirestoreRecyclerOptions} for configuration options.
     *
     * @param options
     */
    public DobbyAdapter(@NonNull FirestoreRecyclerOptions<Dobby> options) {
        super(options);
    }

    @Override
    protected void onBindViewHolder(@NonNull DobbyHolder holder, int position, @NonNull Dobby model) {
        holder.textViewName.setText(model.getName());
        holder.textViewAddress.setText(model.getAddress());
        holder.textViewDistance.setText(model.getDistance());
    }

    @NonNull
    @Override
    public DobbyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.itemdobby, parent, false);
        return new DobbyHolder(v);
    }

    class DobbyHolder extends RecyclerView.ViewHolder{
        TextView textViewName;
        TextView textViewAddress;
        TextView textViewDistance;

        public DobbyHolder(@NonNull View itemView) {
            super(itemView);
            textViewName = itemView.findViewById(R.id.nameDobby);
            textViewAddress = itemView.findViewById(R.id.addressDobby);
            textViewDistance = itemView.findViewById(R.id.distanceDobby);

            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int position = getAdapterPosition();
                    if(position != RecyclerView.NO_POSITION && listener != null){
                        listener.onItemClick(getSnapshots().getSnapshot(position), position);
                    }
                }
            });
        }
    }

    public interface OnItemClickListener {
        void onItemClick(DocumentSnapshot documentSnapshot, int position);
    }

    public void setOnItemClickListener(OnItemClickListener listener){
        this.listener = listener;
    }
}

But the dialog box always pop up indicating that the count is zero even though there is data inside of the recycler view. How can I fix this?

Upvotes: 1

Views: 107

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598728

My guess is that the dialog you're talking about comes from here:

if(adapter.getItemCount() == 0){
    dialog.show();
}

If so, it makes sense that it shows up as this code runs before any data has been loaded.


Data is loaded from Firestore (and most modern cloud APIs) asynchronously, and this changes the order in which code executes. It's easiest to see this if you set breakpoint on the if line above, on adapter.startListening(); and on the first line inside your onBindViewHolder.

If you now run the code in the debugger, you'll see that it:

  1. First hits the if(adapter.getItemCount() == 0){ line
  2. Then adapter.startListening()`
  3. Then gets to onBindViewHolder

So now it hopefully makes sense why your code always show the dialog: no data has been loaded yet at that point.


The solution for this is always the same: you need to make sure that the code that needs the data runs after the data has been loaded. Since you're using the FirestoreRecyclerAdapter from FirebaseUI, you can do this inside its onDataChanged method that signals that a complete snapshot was loaded (regardless of whether there was any data in that snapshot) and is shown in the documentation on data and error events.

So if you move your if check into a onDataChanged method in your DobbyAdapter, it will get called whenever the adapter has loaded a complete snapshot, and it will show the dialog when there are no items.

Upvotes: 1

Related Questions