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

如何避免Firestore在onDataChanged时重置查询数据?

Firestore筛选后数据变更导致结果总数异常

问题描述

给应用添加了筛选功能,可获取特定课程的所有学生并显示结果总数。但数据库数据发生变更时,显示的结果总数不再基于当前查询:

  • 初始加载:Firestore返回20名学生,总数显示正确
  • 筛选BSCS学生:返回5名,总数显示正确
  • 修改某学生的fullName后,总数错误显示为20名,推测onDataChanged()触发时查询被重置为全量查询

问题代码

private void load() {
    Query query = createQuery();
    FirestoreRecyclerOptions<Student> options = new FirestoreRecyclerOptions.Builder<Student>()
            .setQuery(query, Student.class)
            .build();

    myStudentAdapter = new MyStudentAdapter(options){
        @Override
        public void onDataChanged() {
            super.onDataChanged();
            tv_total.setText(String.valueOf(getItemCount()));
        }
    };
    rv.setAdapter(myStudentAdapter);
    myStudentAdapter.startListening();
}

private Query createQuery() {
    if (!search.isEmpty()) {
        if (!course.isEmpty() && !year.isEmpty() && !block.isEmpty()) {
            return db.collection("Student")
                    .orderBy("fullName")
                    .whereEqualTo("course", course)
                    .whereEqualTo("year", year)
                    .whereEqualTo("block", block)
                    .startAt(search)
                    .endAt(search + '\uf8ff');
        } else if (!course.isEmpty() && !year.isEmpty() && block.isEmpty()) {
            return db.collection("Student")
                    .orderBy("fullName")
                    .whereEqualTo("course", course)
                    .whereEqualTo("year", year)
                    .startAt(search)
                    .endAt(search + '\uf8ff');
        } else if (!course.isEmpty() && year.isEmpty() && !block.isEmpty()) {
            return db.collection("Student")
                    .orderBy("fullName")
                    .whereEqualTo("course", course)
                    .whereEqualTo("block", block)
                    .startAt(search)
                    .endAt(search + '\uf8ff');
        } else if (course.isEmpty() && !year.isEmpty() && !block.isEmpty()) {
            return db.collection("Student")
                    .orderBy("fullName")
                    .whereEqualTo("year", year)
                    .whereEqualTo("block", block)
                    .startAt(search)
                    .endAt(search + '\uf8ff');
        } else if (!course.isEmpty() && year.isEmpty() && block.isEmpty()) {
            return db.collection("Student")
                    .orderBy("fullName")
                    .whereEqualTo("course", course)
                    .startAt(search)
                    .endAt(search + '\uf8ff');
        } else if (course.isEmpty() && !year.isEmpty() && block.isEmpty()) {
            return db.collection("Student")
                    .orderBy("fullName")
                    .whereEqualTo("year", year)
                    .startAt(search)
                    .endAt(search + '\uf8ff');
        } else if (course.isEmpty() && year.isEmpty() && !block.isEmpty()) {
            return db.collection("Student")
                    .orderBy("fullName")
                    .whereEqualTo("block", block)
                    .startAt(search)
                    .endAt(search + '\uf8ff');
        } else {
            return db.collection("Student")
                    .orderBy("fullName")
                    .startAt(search)
                    .endAt(search + '\uf8ff');
        }
    } else {
        if (!course.isEmpty() && !year.isEmpty() && !block.isEmpty()) {
            return db.collection("Student")
                    .orderBy("fullName")
                    .whereEqualTo("course", course)
                    .whereEqualTo("year", year)
                    .whereEqualTo("block", block);
        } else if (!course.isEmpty() && !year.isEmpty() && block.isEmpty()) {
            return db.collection("Student")
                    .orderBy("fullName")
                    .whereEqualTo("course", course)
                    .whereEqualTo("year", year);
        } else if (!course.isEmpty() && year.isEmpty() && !block.isEmpty()) {
            return db.collection("Student")
                    .orderBy("fullName")
                    .whereEqualTo("course", course)
                    .whereEqualTo("block", block);
        } else if (course.isEmpty() && !year.isEmpty() && !block.isEmpty()) {
            return db.collection("Student")
                    .orderBy("fullName")
                    .whereEqualTo("year", year)
                    .whereEqualTo("block", block);
        } else if (!course.isEmpty() && year.isEmpty() && block.isEmpty()) {
            return db.collection("Student")
                    .orderBy("fullName")
                    .whereEqualTo("course", course);
        } else if (course.isEmpty() && !year.isEmpty() && block.isEmpty()) {
            return db.collection("Student")
                    .orderBy("fullName")
                    .whereEqualTo("year", year);
        } else if (course.isEmpty() && year.isEmpty() && !block.isEmpty()) {
            return db.collection("Student")
                    .orderBy("fullName")
                    .whereEqualTo("block", block);
        } else {
            return db.collection("Student")
                    .orderBy("fullName");
        }
    }
}

解决方案

1. 停止旧适配器监听,避免多实例冲突

每次创建新适配器前,停止旧适配器的监听,防止旧的全量查询适配器在数据变更时覆盖总数:

private void load() {
    // 先停止旧适配器的监听
    if (myStudentAdapter != null) {
        myStudentAdapter.stopListening();
    }
    
    Query query = createQuery();
    FirestoreRecyclerOptions<Student> options = new FirestoreRecyclerOptions.Builder<Student>()
            .setQuery(query, Student.class)
            .build();

    myStudentAdapter = new MyStudentAdapter(options){
        @Override
        public void onDataChanged() {
            super.onDataChanged();
            tv_total.setText(String.valueOf(getItemCount()));
        }
    };
    rv.setAdapter(myStudentAdapter);
    myStudentAdapter.startListening();
}

2. 简化查询构建逻辑,减少出错概率

将createQuery()重构为链式调用,避免重复代码,降低条件判断出错的可能:

private Query createQuery() {
    CollectionReference studentsRef = db.collection("Student").orderBy("fullName");
    Query query = studentsRef;

    // 依次添加课程、年级、班级筛选条件
    if (!course.isEmpty()) {
        query = query.whereEqualTo("course", course);
    }
    if (!year.isEmpty()) {
        query = query.whereEqualTo("year", year);
    }
    if (!block.isEmpty()) {
        query = query.whereEqualTo("block", block);
    }

    // 添加搜索前缀匹配
    if (!search.isEmpty()) {
        query = query.startAt(search).endAt(search + '\uf8ff');
    }

    return query;
}

3. 确保筛选变量稳定

确认course、year、block、search为类成员变量,且在数据变更操作中不会被意外重置为空值。


内容的提问来源于stack exchange,提问作者Vince Ybañez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 06:01:44