Запустить второй запрос из LiveData и объединить результаты (Firestore)? - PullRequest
0 голосов
/ 24 мая 2018

У меня есть две коллекции: пользователи и книги.Мне нужно получить результаты обоих из них, независимо от того, обновлены ли пользователи или книги, а затем объединить результаты вместе в LinkedHashMap для использования в качестве меню listView.

Я думал, что MediatorLiveData будет подходить, ноесли я помещу запрос Users и Query of Books в то, я получаю нулевое значение от одного из двух объектов LiveData, потому что срабатывает только один или другой.Я подумал, может быть, если один из них сработает, тогда, возможно, у меня есть запрос, запускаемый внутри каждого addSource () в MediatorLiveData, но я не уверен, что это путь.

Мой пост, касающийся MediatorLiveData,здесь: Использование MediatorLiveData для слияния с LiveData (Firestore) Потоки QuerySnapshot дают странные результаты

Мои два запроса и объекты 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()); 

Почему-то, когдаПользователи обновляются, мне нужно также получать данные Книг, а затем объединять их, но мне также нужно, чтобы это происходило, если Книги обновляют, а затем получают данные Пользователей и объединяют их.

Любые идеи будут в значительной степениприветствуется.

Дополнительное примечание / наблюдение Хорошо, поэтому я не полностью исключаю объект MediatorLiveData.Конечно, это позволяет мне прослушивать два разных объекта 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.Вместо этого мне нужно запросить затем объединить.Есть идеи, как это сделать?В этом нет ничего особенного.

Я пытался поместить запрос в функцию, которая вызывается с использованием Transformations.map (), но из-за асинхронного вызова оператор return выполняетсяВызван до завершения запроса.

Вот моя попытка функции:

    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 ]

0 голосов
/ 25 мая 2018

Вот простая версия того, что вы могли бы сделать, надеюсь, в этом есть смысл.

Вы близки с 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!
        // ...
    }

});
0 голосов
/ 26 мая 2018

Я думаю, что решил это.Мы объявляли новый объект MyResult в каждом методе mediatorLiveData.addSource ().Это означало, что мы получали новый объект для каждого 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;
    } 

Теперь я получаюпользователи и книги в обозревателе в Activity!Теперь единственное, что мне нужно сделать, - это преобразовать (объединить данные) в LinkedHashMap, но, думаю, я понял это.Спасибо Сэм!

0 голосов
/ 24 мая 2018

Итак, я здесь с вашими предложениями, Сэм.

Я добавил методы getter и setter в класс MyResult, так как в противном случае он не давал мне доступ к переменным-членам в наблюдателе:

    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 ();как метод инициализации и получения.

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 запускает другой запрос.Имеет ли это смысл?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...