Как сделать несколько запросов, используя retrofit2 и rxjava2 на Android? - PullRequest
0 голосов
/ 27 января 2019

В моем приложении для Android я хочу сделать несколько http-запросов, используя retrofit и rxjava для получения данных json.Количество запросов зависит от предпочтений пользователя (от 1 до 40).Каждый запрос независим и возвращает один и тот же тип.Итак, я попытался применить способ, рекомендованный в этом вопросе ( Как сделать несколько запросов и дождаться получения данных от всех запросов в модификации 2.0 - Android ), которая использует функцию zip rx-Джава.Но я не мог найти способ получить и объединить результаты каждого запроса.Тип ответа, который я использовал для отдельного запроса при модернизации, был Response<List<NewsItem>>, где NewsItem - мой пользовательский объект.(ответ на самом деле - массив json, но в одном запросе модификация автоматически обрабатывает его и преобразует в список моих пользовательских объектов). Ниже я попробовал следующее:

Мой интерфейс API

public interface API {

    String BASE_URL = "xxx/";

    @GET("news/{source}")
    Observable<List<NewsItem>> getNews(@Path("source") String source);
}

Класс Viewmodel для извлечения данных

public class NewsVM extends AndroidViewModel {

    public NewsVM(Application application){
        super(application);
    }

    private MutableLiveData<List<NewsItem>> newsLiveData;

    public LiveData<List<NewsItem>> getNewsLiveData(ArrayList<String> mySourceList) {

        newsLiveData = new MutableLiveData<>();
        loadNews(mySourceList);

        return newsLiveData;
    }

    private void loadNews(ArrayList<String> mySourceList) {

        Gson gson = new GsonBuilder().setLenient().create();

        Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(API.BASE_URL)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build();

        API api = retrofit.create(API.class);

        //Gathering the requests into list of observables
        List<Observable<?>> requests = new ArrayList<>();
        for(String source: mySourceList){
            requests.add(api.getNews(source));
        }

        // Zip all requests
        Observable.zip(requests, new Function<Object[], List<NewsItem>>() {
            @Override
            public List<NewsItem> apply(Object[] objects) throws Exception {

                // I am not sure about the parameters and return type in here, probably wrong 
                return new ArrayList<>();
            }
        })
            .subscribeOn(Schedulers.io())
            .observeOn(Schedulers.newThread())
            .subscribe(
                new Consumer<List<NewsItem>>() {
                    @Override
                    public void accept(List<NewsItem> newsList) throws Exception {

                        Log.d("ONRESPONSE",newsList.toString());
                        newsLiveData.setValue(newsList);
                    }
                },
                new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable e) throws Exception {

                        Log.d("ONFAILURE", e.getMessage());
                    }
                }
        ).dispose();

    }
}

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

Ответы [ 3 ]

0 голосов
/ 28 января 2019

Если тип данных , который вы получаете, совпадает Список , а запросы несколько, то вы можете использовать Метод рекурсии, чтобы сделать 1n запросов и добавление данных Список при каждом успехе.

0 голосов
/ 29 января 2019

попробуйте использовать Observable.from(Iterable<? extends T> iterable) (Observable.fromArray() в rx-java2) вместо zip Так что у вас будет что-то вроде:

Observable.from(mySourceList)
    .flatMap(new Func1<String, Observable<List<NewsItem>>>() {
        @Override
           public Observable<List<NewsItem>> call(String source) {
                return api.getNews(source);
            }
        })
        .subscribeOn(Schedulers.io())
        .observeOn(Schedulers.newThread())
        .toList() // This will give you List<List<NewsItem>>
        .map(new Func1<List<List<NewsItem>>, List<NewsItem>>() {
            @Override
            public List<NewsItem> call(List<List<NewsItem>> listOfList) {
                //Merged list of lists to single list using Guava Library
                List<NewsItem> list = Lists.newArrayList(Iterables.concat(listOfList));
                return list;
            }
        })
        .subscribe(new Subscriber<List<NewsItem>>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
            }

            @Override
            public void onNext(List<NewsItem> newsList) {
                //Attached the final newslist to livedata
                newsLiveData.setValue(newsList);
            }
        });

EDITED Обновлен метод

0 голосов
/ 28 января 2019

Object[] objects - массив элементов, возвращаемых запросами.Предполагая, что каждый ваш запрос возвращает List<NewsItem> и вы хотите объединить все NewsItem в один List<NewsItem>, я думаю, что вы можете сделать что-то вроде:

private void loadNews(ArrayList<String> mySourceList) {
    ...
    // Zip all requests
    Observable.zip(requests, new Function<Object[], List<NewsItem>>() {
        @Override
        public List<NewsItem> apply(Object[] objects) throws Exception {
            List<NewsItem> combinedNewsItems = new ArrayList<>();
            for (Object response : objects) {
                combinedNewsItems.addAll((List<NewsItem>) response);
            }
            return combinedNewsItems;
        }
    })
        .subscribeOn(Schedulers.io())
        ...
}

Будьте в курсетип литья.

...