使用MediatorLiveData合并Firestore的QuerySnapshot流出现异常结果
问题根源分析
你当前的实现有两个核心问题:
- MediatorLiveData只传递单一数据源的快照:每次
usersLiveData或booksLiveData更新时,你直接把当前的QuerySnapshot设为mediatorLiveData的值,导致观察者每次只能拿到其中一组数据的快照,另一组数据用这个快照转换自然会得到字段为null的对象(因为Firestore文档结构和目标实体类不匹配)。 - 没有维护数据源的最新状态:每次触发回调时,你没有保存之前的用户/书籍数据,所以当第二个数据源更新时,无法合并两组完整的数据,反而会因为多次触发回调导致日志里出现重复的输出。
解决方案
我们需要修改实现,让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
相关产品推荐
相关产品推荐

