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

如何触发LiveData二次查询并合并Firestore双集合更新结果?

解决Firestore双集合更新时合并数据的问题

我懂你现在遇到的麻烦了:用MediatorLiveData的时候,每次只有一个数据源触发更新,另一个总是返回null,而且在Transformations.map里做异步查询根本得不到正确结果——这都是因为异步操作的特性,加上你之前的MediatorLiveData只是简单转发单个快照导致的。

核心思路应该是:先缓存两个集合的最新数据,只有当两者都持有有效数据时,再执行合并操作。下面是具体的实现方案:


第一步:重构MediatorLiveData实现

修改你的usersBooksLiveDataMerger方法,让它缓存两个数据源的快照,每次任一数据源更新时,先更新缓存,再检查是否可以执行合并:

private MediatorLiveData<LinkedHashMap<User, List<Book>>> usersBooksLiveDataMerger() {
    final MediatorLiveData<LinkedHashMap<User, List<Book>>> mergedLiveData = new MediatorLiveData<>();
    
    // 缓存两个集合的最新快照
    QuerySnapshot usersCache = null;
    QuerySnapshot booksCache = null;

    // 监听用户集合的更新
    mergedLiveData.addSource(usersLiveData, new Observer<QuerySnapshot>() {
        @Override
        public void onChanged(@Nullable QuerySnapshot usersSnapshot) {
            usersCache = usersSnapshot;
            // 尝试合并并发送数据
            attemptMerge(usersCache, booksCache, mergedLiveData);
        }
    });

    // 监听书籍集合的更新
    mergedLiveData.addSource(booksLiveData, new Observer<QuerySnapshot>() {
        @Override
        public void onChanged(@Nullable QuerySnapshot booksSnapshot) {
            booksCache = booksSnapshot;
            // 尝试合并并发送数据
            attemptMerge(usersCache, booksCache, mergedLiveData);
        }
    });

    return mergedLiveData;
}

第二步:实现合并逻辑

单独抽离合并方法,确保只有当两个快照都非空时,才执行你需要的映射逻辑:

private void attemptMerge(QuerySnapshot usersSnapshot, QuerySnapshot booksSnapshot,
                          MediatorLiveData<LinkedHashMap<User, List<Book>>> targetLiveData) {
    // 只有两个快照都有效时才继续
    if (usersSnapshot == null || booksSnapshot == null) {
        return;
    }

    // 转换为实体类列表
    List<User> userList = usersSnapshot.toObjects(User.class);
    List<Book> bookList = booksSnapshot.toObjects(Book.class);
    
    LinkedHashMap<User, List<Book>> userBookMap = new LinkedHashMap<>();

    // 执行你原本的合并逻辑
    for (User user : userList) {
        List<Book> assignedBooks = new ArrayList<>();
        for (Book book : bookList) {
            if ((user.getUserID().equals(book.getUserID()) && book.getBookAssigned())
                || user.getAllBookID().equals(book.getBookID())) {
                assignedBooks.add(book);
            }
        }
        userBookMap.put(user, assignedBooks);
    }

    // 发送合并后的结果给观察者
    targetLiveData.setValue(userBookMap);
}

为什么这个方案能解决你的问题?

  1. 缓存机制:每次任一集合更新时,我们先把最新快照缓存起来,不会丢失另一个集合的已有数据,彻底避免了null的问题。
  2. 实时合并:不管是Users还是Books集合更新,都会触发合并逻辑,保证ListView的数据源始终是最新的完整数据。
  3. 规避异步坑:我们不需要在合并时手动调用get()做单次查询,而是依赖FirebaseQueryLiveData的实时监听,完全适配LiveData的生命周期特性。

额外小提示

如果你的FirebaseQueryLiveData在初始化时会发送一次初始数据(哪怕集合是空的),那这个方案会在两个初始数据都到达后,自动生成第一个合并结果,完美适配ListView的初始化需求。

内容的提问来源于stack exchange,提问作者Brian Begun

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:04:31