代码之家  ›  专栏  ›  技术社区  ›  Brian Begun

是否从LiveData触发第二个查询并合并结果(FireStore)?

  •  2
  • Brian Begun  · 技术社区  · 6 年前

    我有两个收藏:用户和书籍。无论是更新用户还是书籍,我都需要获取它们的结果,然后将结果合并到LinkedHashMap中,用作ListView菜单。

    我认为中介LiveData是可行的,但是如果我将用户查询和图书查询放在其中,那么两个LiveData对象中的一个将得到空值,因为只有一个或其他对象触发。我想如果其中一个触发了,那么可能我在mediatorLiveData中的每个addSource()内部都运行了一个查询,但是我不确定这是否是解决问题的方法。

    我关于mediatorlivedata的帖子如下: Using MediatorLiveData to merge to LiveData (Firestore) QuerySnapshot streams is producing weird results

    我的两个查询和LiveData对象如下:

    //getUsers query using FirebaseQueryLiveData class
    private Query getUsersQuery() {
        FirebaseAuth mAuth = FirebaseAuth.getInstance();
    
        adminID = mAuth.getUid();
        query = FirebaseFirestore.getInstance().collection("admins")
                .document(adminID)
                .collection("users")
        return query;
    }
    
    private FirebaseQueryLiveData usersLiveData = new FirebaseQueryLiveData(getUsersQuery());
    
    
    //getBooks query using FirebaseQueryLiveData class
    private Query getBooksQuery () {
        FirebaseGroupID firebaseGroupID = new FirebaseGroupID(getApplication());
        groupID = firebaseGroupID.getGroupID();
        query = FirebaseFirestore.getInstance().collection("books")
                .whereEqualTo("groupID", groupID)      
        return query;
    }
    
    private FirebaseQueryLiveData booksLiveData = new FirebaseQueryLiveData(getBooksQuery()); 
    

    不知何故,当用户更新时,我也需要获取书籍的数据,然后合并它们,但如果书籍更新,然后获取用户的数据并合并它们,我也需要这样做。

    任何想法都会受到极大的赞赏。

    附加说明/观察 好吧,所以我不完全排除中介LiveData对象。当然,它允许我在同一个方法中监听两个不同的LiveData对象,但是,我不想直接合并这两个对象,因为我需要单独处理每个LiveData对象。例如:userslivedata触发是因为我们创建或修改了一个用户,然后我需要查询书籍,获取结果,并合并用户和书籍等。

    以下是我目前的mediatorlivedata:

    //MediatorLiveData merge two LiveData QuerySnapshot streams
    private MediatorLiveData<QuerySnapshot> usersBooksLiveDataMerger() {
        final MediatorLiveData<QuerySnapshot> mediatorLiveData = new MediatorLiveData<>();
        mediatorLiveData.addSource(usersLiveData, new Observer<QuerySnapshot>() {
            @Override
            public void onChanged(@Nullable QuerySnapshot querySnapshot) {
                mediatorLiveData.setValue(querySnapshot);
            }
        });
        mediatorLiveData.addSource(booksLiveData, new Observer<QuerySnapshot>() {
            @Override
            public void onChanged(@Nullable QuerySnapshot querySnapshot) {
                mediatorLiveData.setValue(querySnapshot);
            }
        });
        return mediatorLiveData;
    }
    

    现在它返回另一个LiveData源的空结果。相反,我需要查询然后合并。有什么办法吗?在这件事上没有太多。

    我尝试将一个查询放入一个使用transforms.map()调用的函数中,但是由于它是异步调用,所以在查询完成之前调用返回语句。

    以下是我对该功能的尝试:

        private class ListenUsersGetBooks implements Function<QuerySnapshot, LinkedHashMap<User, List<Book>>> {
    
            @Override
            public LinkedHashMap<User, List<Book>> apply(final QuerySnapshot input) {
                userBookList = new LinkedHashMap<>();
                getBooksQuery().get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                    @Override
                    public void onComplete(@NonNull Task<QuerySnapshot> task) {
                        List<User> users = input.toObjects(User.class);
                        List<Book> books = task.getResult().toObjects(Book.class);
                        Log.d(TAG, "USERLIST! " + users);
                        Log.d(TAG, "BOOKLIST! " + books);
                        for (User user : users) {
                            bookList = new ArrayList<>();
                            for (Book book : books) {
                                if (user.getUserID().equals(book.getUserID())
                                        && book.getBookAssigned()) {
                                    bookList.add(book);
                                }
                                else if (user.getAllBookID().equals(book.getBookID())) {
                                    bookList.add(book);
                                }
                            }
                            userBookList.put(user, bookList);
                        }
                        Log.d(TAG,"OBSERVE userBookList: " + userBookList);
                    }
                });
                return userBookList;
            }
        } 
    
    3 回复  |  直到 6 年前
        1
  •  2
  •   Sam Stern    6 年前

    这里有一个简单的版本,你可以做什么,我希望它是有意义的。

    你很接近 MediatorLiveData . 而不是 MediatorLiveData<QuerySnapshot> 您可能希望使用这样的自定义对象:

    class MyResult {
    
      public QuerySnapshot usersSnapshot;
      public QuerySnapshot booksSnapshot;
    
      public MyResult() {}
    
      boolean isComplete() {
        return (usersSnapshot != null && booksSnapshot != null);
      }
    }
    

    然后在你的观察者中,做如下的事情:

    private MediatorLiveData<MyResult> usersBooksLiveDataMerger() {
        final MediatorLiveData<MyResult> mediatorLiveData = new MediatorLiveData<>();
        mediatorLiveData.addSource(usersLiveData, new Observer<QuerySnapshot>() {
            @Override
            public void onChanged(@Nullable QuerySnapshot querySnapshot) {
                MyResult current = mediatorLiveData.getValue();
                current.usersSnapshot = querySnapshot;
                mediatorLiveData.setValue(current);
            }
        });
        mediatorLiveData.addSource(booksLiveData, new Observer<QuerySnapshot>() {
            @Override
            public void onChanged(@Nullable QuerySnapshot querySnapshot) {
                MyResult current = mediatorLiveData.getValue();
                current.booksSnapshot = querySnapshot;
                mediatorLiveData.setValue(current);
            }
        });
        return mediatorLiveData;
    }
    

    然后,当您观察组合的实时数据时:

    usersBooksLiveDataMerger().observe(new Observer<MyResult>() {
    
        @Override
        public void onChanged(@Nullable MyResult result) {
            if (result == null || !result.isComplete()) {
              // Ignore, this means only one of the queries has fininshed
              return;
            }
    
            // If you get to here, you know all the queries are ready!
            // ...
        }
    
    });
    
        2
  •  1
  •   Brian Begun    6 年前

    我想我解决了。我们在每个mediatorLiveData.addSource()方法中声明了一个新的myresult对象。这意味着我们将为每个querysnapshot获取一个新的对象,这样我们就不会让它们彼此合并。

    以下是MediatorLiveData的更新:

        private MediatorLiveData<MyResult> usersBooksLiveDataMerger() {
            final MediatorLiveData<MyResult> mediatorLiveData = new MediatorLiveData<>();
            final MyResult current = new MyResult();
            mediatorLiveData.addSource(usersLiveData, new Observer<QuerySnapshot>() {
                @Override
                public void onChanged(@Nullable QuerySnapshot querySnapshot) {
                    current.setUsersSnapshot(querySnapshot);
                    mediatorLiveData.setValue(current);
                }
            });
            mediatorLiveData.addSource(booksLiveData, new Observer<QuerySnapshot>() {
                @Override
                public void onChanged(@Nullable QuerySnapshot querySnapshot) {
                    current.setBooksSnapshot(querySnapshot);
                    mediatorLiveData.setValue(current);
                }
            });
            return mediatorLiveData;
        } 
    

    现在我让用户和书籍在观察员的活动中!现在我唯一需要做的就是将数据转换(合并)成LinkedHashMap,但我想我已经弄明白了。谢谢山姆!

        3
  •  0
  •   Brian Begun    6 年前

    所以这就是我对你的建议,山姆。

    我在myresult类中添加了getter和setter方法,因为它不允许我访问观察者中的成员变量,否则:

        public class MyResult {
    
            QuerySnapshot usersSnapshot;
            QuerySnapshot booksSnapshot;
    
            //default constructor
            public MyResult() {
            }
    
            public QuerySnapshot getUsersSnapshot() {
                return usersSnapshot;
            }
    
            public void setUsersSnapshot(QuerySnapshot usersSnapshot) {
                this.usersSnapshot = usersSnapshot;
            }
    
            public QuerySnapshot getBooksSnapshot() {
                return booksSnapshot;
            }
    
            public void setBooksSnapshot(QuerySnapshot booksSnapshot) {
                this.booksSnapshot = booksSnapshot;
            }
    
            public boolean isComplete() {
                return (usersSnapshot != null && booksSnapshot != null);
            }
        } 
    

    这是mediatorLiveData和get方法。我将myresult类初始化更改为=new myresult();认为使用mediatorLiveData.getValue()作为初始化和get方法时出现问题。

    private MediatorLiveData<MyResult> usersBooksLiveDataMerger() {
        final MediatorLiveData<MyResult> mediatorLiveData = new MediatorLiveData<>();
        mediatorLiveData.addSource(usersLiveData, new Observer<QuerySnapshot>() {
            @Override
            public void onChanged(@Nullable QuerySnapshot querySnapshot) {
                MyResult current = new MyResult();
                current.setUsersSnapshot(querySnapshot);
                mediatorLiveData.setValue(current);
            }
        });
        mediatorLiveData.addSource(booksLiveData, new Observer<QuerySnapshot>() {
            @Override
            public void onChanged(@Nullable QuerySnapshot querySnapshot) {
                MyResult current = new MyResult();
                current.setBooksSnapshot(querySnapshot);
                mediatorLiveData.setValue(current);
            }
        });
        return mediatorLiveData;
    }
    
    public MediatorLiveData<MyResult> getUsersBooksLiveDataMerger() {
        return usersBooksLiveDataMerger();
    }
    

    最后,观察员:

        mainViewModel.getUsersBooksLiveDataMerger().observe(this, new Observer<MainViewModel.MyResult>() {
                @Override
                public void onChanged(@Nullable MainViewModel.MyResult myResult) {
                    if (myResult == null || !myResult.isComplete()) {
                        // Ignore, this means only one of the queries has fininshed
                        Log.d(TAG, "OBSERVE BLAH!!!!");
                        return;
                    }
    
                    // If you get to here, you know all the queries are ready!
                    // ...
                    List<Book> books;
                    List<User> users;
                    books = myResult.getBooksSnapshot().toObjects(Book.class);
                    users = myResult.getUsersSnapshot().toObjects(User.class);
                    Log.d(TAG, "OBSERVE MERGE users: " + users);
                    Log.d(TAG, "OBSERVE MERGE books: " + books);
                }
            }); 
    

    请注意:我在mediatorlivedata中做了一个空检查,只是出于测试目的将其取出。

    不知何故,如果只触发了我的用户,我就需要触发我的图书查询;如果只触发了我的图书,我就需要触发我的用户查询……我觉得在需要执行MediatorLiveData之前有一个步骤,这样我们就可以确保一个LiveData触发另一个查询。这有道理吗?