You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用FirestoreRecyclerAdapter时getItemCount()始终返回0的解决方法

问题:FirestoreRecyclerAdapter数据存在时仍弹出无数据对话框

我正在开发一款洗衣设备预订应用,需要在条目数量为0时向用户显示无数据提示对话框。但目前即使RecyclerView中有数据,对话框仍会弹出,请问该如何修复?

Activity代码

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代码

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;
    }
}

解决方案

问题根源

FirestoreRecyclerAdapter的getItemCount()在初始化阶段会返回0,因为Firestore的数据是异步加载的。你在setUpRecyclerView()中立即调用adapter.getItemCount()时,数据还未从云端拉取完成,因此这个判断永远会触发对话框弹出,和实际数据是否存在无关。

修复步骤

我们需要利用FirestoreRecyclerAdapter提供的onDataChanged()方法——这个方法会在数据首次加载完成、或者数据发生变化时被调用,此时可以准确获取实际的条目数量。

1. 修改Adapter,添加数据加载回调

在Adapter中新增一个回调接口,用于通知Activity数据加载完成,并在onDataChanged()中触发该回调:

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

    private OnItemClickListener listener;
    private OnDataLoadedListener dataLoadedListener; // 新增数据加载回调

    public DobbyAdapter(@NonNull FirestoreRecyclerOptions<Dobby> options) {
        super(options);
    }

    // 新增设置回调的方法
    public void setOnDataLoadedListener(OnDataLoadedListener listener) {
        this.dataLoadedListener = listener;
    }

    @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);
    }

    // 重写onDataChanged,数据加载/变化时触发
    @Override
    public void onDataChanged() {
        super.onDataChanged();
        if (dataLoadedListener != null) {
            dataLoadedListener.onDataLoaded(getItemCount());
        }
    }

    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;
    }

    // 新增数据加载完成的回调接口
    public interface OnDataLoadedListener {
        void onDataLoaded(int itemCount);
    }
}

2. 修改Activity,监听数据加载状态

移除setUpRecyclerView()中原来的if(adapter.getItemCount() == 0)判断,改为通过Adapter的回调来处理对话框显示:

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 CustomLinearLayoutManager(this));
    recyclerView.setAdapter(adapter);

    // 移除原来的错误判断逻辑
    // if(adapter.getItemCount() == 0){
    //     dialog.show();
    // }

    // 添加数据加载完成监听
    adapter.setOnDataLoadedListener(new DobbyAdapter.OnDataLoadedListener() {
        @Override
        public void onDataLoaded(int itemCount) {
            if (itemCount == 0) {
                if (!dialog.isShowing()) {
                    dialog.show();
                }
            } else {
                if (dialog.isShowing()) {
                    dialog.dismiss();
                }
            }
        }
    });

    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);
        }
    });
}

效果说明

修改后,只有当Firestore数据加载完成且确实没有数据时,才会弹出无数据对话框。如果数据加载成功且有内容,对话框会自动关闭(如果之前因异步加载误弹的话),同时还能处理数据动态变化的场景(比如数据被全部删除后,对话框会重新弹出)。


内容的提问来源于stack exchange,提问作者Haziq Mt Roslan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 18:35:25