Дождитесь асинхронного c вызова до завершения sh с Android LiveData - PullRequest
0 голосов
/ 11 марта 2020

Я разрабатываю приложение Android с использованием архитектуры MVVM. Это функция, которая возвращает MutableLiveData из моего репозитория для наблюдения из ViewModel.

    public MutableLiveData<ArrayList<CoffeeShop>> getCoffeeShops(){
        setCoffeeShops();
        MutableLiveData<ArrayList<CoffeeShop>> data = new MutableLiveData<>();
        data.setValue(coffeeShops);
        return data;
    }

    public void setCoffeeShops() {
        CollectionReference coffeeShopsRef = database.collection("coffee_shops");
        coffeeShopsRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>(){
            @Override
            public void onComplete(@NonNull Task< QuerySnapshot > task) {
                if (task.isSuccessful()) {
                    for (QueryDocumentSnapshot document : task.getResult()) {
                        CoffeeShop coffeeShop = new CoffeeShop();
                        coffeeShop.setName((String) document.get("name"));
                        coffeeShop.setLocation((GeoPoint) document.get("location"));
                        coffeeShop.setOffers((ArrayList<String>) document.get("offers"));
                        coffeeShop.setRating((Long) document.get("rating"));
                        coffeeShop.setReviews((ArrayList<Review>) document.get("reviews"));
                        coffeeShops.add(coffeeShop);
                    }
                }
            }
        });
    }

Функция setCoffeeShops () выполняет асинхронный вызов c в базу данных и устанавливает значение для coffeeShops переменная. Мне нужно найти способ дождаться разрешения вызова asyn c и только потом присвоить значение объекту MutableLiveData. Это правильный подход к проблеме, и если да, что бы вы порекомендовали?

Спасибо!

Ответы [ 2 ]

0 голосов
/ 12 марта 2020

Я хочу порекомендовать Room каркас базы данных. Он поддерживает Livedata, а также имеет отличный ORMapper. Таким образом, с помощью простой объектной модели вы можете достичь цели и сократить объем кода для достижения цели.

Следующая ссылка показывает вам отличный способ сделать это:

https://codelabs.developers.google.com/codelabs/android-training-livedata-viewmodel/#6

Однако, если у вас нет плана перехода на Помещение, просто измените свой порядок следующим образом:

    public MutableLiveData<ArrayList<CoffeeShop>> getCoffeeShops(){
        MutableLiveData<ArrayList<CoffeeShop>> data = new MutableLiveData<>();
        setCoffeeShops(data);
        return data;
    }

    public void setCoffeeShops(MutableLiveData<ArrayList<CoffeeShop>> data) {
        CollectionReference coffeeShopsRef = database.collection("coffee_shops");
        coffeeShopsRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>(){
            @Override
            public void onComplete(@NonNull Task< QuerySnapshot > task) {
                if (task.isSuccessful()) {
                    for (QueryDocumentSnapshot document : task.getResult()) {
                        CoffeeShop coffeeShop = new CoffeeShop();
                        /* data conversion code*/
                        coffeeShops.add(coffeeShop);
                    }

                    //If runs on main thread 
                    data.setValue(coffeeShops)

                    //Otherwise
                    data.postValue(coffeeShops) 

                    //Use one of top lines base on the situation
                }
            }
        });
    }

Теперь вам не нужно ждать сбора данных, изменения будут спроектированы, как только данные будут готовы в методе прослушивателя.

0 голосов
/ 11 марта 2020

Попробуйте это:

Примите параметр обратного вызова для setCoffeeShops ()

например: setCoffeeShops(Runnable callback)

И когда ваши установленные кофейни будут завершены, вызовите обратный вызов:

callback.run()

И когда вы вызываете setCoffeeShops, делайте это так:

MutableLiveData<ArrayList<CoffeeShop>> data = new MutableLiveData<>();
setCoffeeShops(()->{  
    data.setValue(coffeeShops);
});
return data;

ИЛИ, чтобы ваш код немного чище, используйте интерфейс вместо того, чтобы сохранять coffeeShops как глобальная переменная, подобная этой:

    interface CoffeeShopLoader {
        void shopsLoaded(List<CoffeeShop> shops);
    }

    void setCoffeeShops(CoffeeShopLoader loader)  {
        ...

        loader.shopsLoaded(coffeeShops);
    }

    ... // and call it like this

       setCoffeeShops((shops)->{
           data.setValue(shops)
       });

    ...

...