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

使用MediatorLiveData合并Firestore的QuerySnapshot流出现异常结果

问题根源分析

你当前的实现有两个核心问题:

  1. MediatorLiveData只传递单一数据源的快照:每次usersLiveData或booksLiveData更新时,你直接把当前的QuerySnapshot设为mediatorLiveData的值,导致观察者每次只能拿到其中一组数据的快照,另一组数据用这个快照转换自然会得到字段为null的对象(因为Firestore文档结构和目标实体类不匹配)。
  2. 没有维护数据源的最新状态:每次触发回调时,你没有保存之前的用户/书籍数据,所以当第二个数据源更新时,无法合并两组完整的数据,反而会因为多次触发回调导致日志里出现重复的输出。
解决方案

我们需要修改实现,让MediatorLiveData同时维护两组数据的最新状态,然后合并成一个完整的对象传递给观察者。

步骤1:创建合并数据类

首先定义一个专门的类,用来封装合并后的用户和书籍数据:

public class UsersAndBooks {
    private List<User> users;
    private List<Book> books;

    public UsersAndBooks(List<User> users, List<Book> books) {
        this.users = users;
        this.books = books;
    }

    // Getter方法
    public List<User> getUsers() {
        return users;
    }

    public List<Book> getBooks() {
        return books;
    }
}

步骤2:修改ViewModel中的MediatorLiveData实现

在ViewModel中保存两组数据的最新状态,当任意一个数据源更新时,合并最新数据并发送给观察者:

// 保存最新的用户和书籍列表
private List<User> currentUsers = new ArrayList<>();
private List<Book> currentBooks = new ArrayList<>();

// 修改MediatorLiveData的泛型为我们的合并类
private MediatorLiveData<UsersAndBooks> usersBooksLiveDataMerger() {
    final MediatorLiveData<UsersAndBooks> mediatorLiveData = new MediatorLiveData<>();

    // 监听用户数据变化
    mediatorLiveData.addSource(usersLiveData, querySnapshot -> {
        if (querySnapshot != null) {
            // 更新当前用户列表
            currentUsers = querySnapshot.toObjects(User.class);
            // 合并最新的两组数据并发送
            mediatorLiveData.setValue(new UsersAndBooks(currentUsers, currentBooks));
        }
    });

    // 监听书籍数据变化
    mediatorLiveData.addSource(booksLiveData, querySnapshot -> {
        if (querySnapshot != null) {
            // 更新当前书籍列表
            currentBooks = querySnapshot.toObjects(Book.class);
            // 合并最新的两组数据并发送
            mediatorLiveData.setValue(new UsersAndBooks(currentUsers, currentBooks));
        }
    });

    return mediatorLiveData;
}

// 更新get方法的返回类型
public MediatorLiveData<UsersAndBooks> getUsersBooksLiveDataMerger() {
    return usersBooksLiveDataMerger();
}

步骤3:修改MainActivity的观察者逻辑

现在观察者可以直接接收合并后的完整数据,不需要再用同一个快照转换两种类型:

mainViewModel.getUsersBooksLiveDataMerger().observe(this, usersAndBooks -> {
    if (usersAndBooks != null) {
        List<User> users = usersAndBooks.getUsers();
        List<Book> books = usersAndBooks.getBooks();
        
        Log.d(TAG, "OBSERVE MERGE users: " + users);
        Log.d(TAG, "OBSERVE MERGE books: " + books);
    }
});

额外优化(可选)

如果想减少不必要的回调(比如数据源重复发送相同数据时),可以在更新currentUsers或currentBooks前,先比对新数据和旧数据是否一致,只有当数据真的变化时才更新并发送合并结果。比如可以用equals方法或者第三方库(如Guava的Lists.equal)来判断列表是否相同。


内容的提问来源于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:03:57