Retrofit & RxJava multiple requests complete

后端 未结 4 2243
盖世英雄少女心
盖世英雄少女心 2021-02-14 10:25

I need to do:

  1. Request 2 lists of news from different websites
  2. Combine results from requests
  3. Sort items by date
  4. Get 10 newest news
  5. <
相关标签:
4条回答
  • 2021-02-14 10:48

    If you don't want to do something specific with the combined results, then merge() is enough:

    Observable<RegionalNews> regionalNews = ...;
    Observable<NationalNews> nationalNews = ...;
    
    Observable
    .merge(regionalNews, nationalNews)
    .ignoreElements()
    .observeOn(AndroidSchedulers.mainThread())
    .doOnComplete(() -> { /* show alert */ })
    .subscribe()
    
    0 讨论(0)
  • 2021-02-14 10:55

    You can use zip operator to call 2 requests async and save or process their data on response.

    For example.

    Below are two Observable

    Observable<ResponseOne> responseOneObservable = getRetrofitClient().getDataOne()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread());
    
    Observable<ResponseTwo> responseTwoObservable = getRetrofitClient().getDataTwo()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread());
    

    Using zip operator on above two Observable as below.

    Observable<ArrayList<TestData>> testDataObservable = Observable.zip(responseOneObservable, responseTwoObservable, new Func2<ResponseOne, ResponseTwo, ArrayList<TestData>>() {
                @Override
                    public ArrayList<TestData> call(ResponseOne responseOne, ResponseTwo responseTwo) {
                      ArrayList<TestData> testDataList = new ArrayList();
                          // process data from response responseOne & responseTwo
                      return testDataList;
                } 
        })
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Subscriber<ArrayList<TestData>>() {
    
            @Override
            public void onNext(ArrayList<TestData> testDataList) {
    
            }
    
            @Override
            public void onCompleted() {
                Log.d(TAG, "onCompleted" ); 
                // you can show alert here or do something when completed 
            }
    
            @Override
            public void onError(Throwable t) {
                Log.d(TAG, "onError Throwable: " + t.toString() );
            }
        });
    
    0 讨论(0)
  • 2021-02-14 10:56

    zip is the way to combine observables. Combining their results is just a consequence.

    If you want to wait for both observables to finish (complete), the easiest way is to use zip. You just don't have to use the results of your requests in the combining function. Just use this function as a way to emit something different when both of those calls finish. When this function emits an item:

    [...] do something when all requests completed (show alert for example)

    For example like this (executing someOtherCall when both of those requests finish):

    Observable<Integer> obs1 = ...;
    Observable<Long> obs2 = ...;
    
    Observable.zip(obs1, obs2, new Func2<Integer, Long, String>() {
        @Override
        public String call(Integer integer, Long aLong) {
            return "something completely different";
        }
    }).flatMap(new Func1<String, Observable<Float>>() {
        @Override
        public Observable<Float> call(String s) {
            return performSomeOtherCall();
        }
    }).subscribe(...);
    
    0 讨论(0)
  • 2021-02-14 11:05

    Well it depends, as always. Do you need to process the returned values down the chain, or just save it?

    In this implementation I use Single and Completable. You subscribe to the completable and you will get notified when both Singles finished.

    @Test
    public void name() throws Exception {
            TestScheduler testScheduler = new TestScheduler();
            Single<Long> request1 = Single.timer(1000, TimeUnit.MILLISECONDS, testScheduler)
                    .doOnSuccess(aLong -> {
                        System.out.println("save to db.");
                    });
            Single<Long> request2 = Single.timer(500, TimeUnit.MILLISECONDS, testScheduler)
                    .doOnSuccess(aLong -> {
                        System.out.println("save to db.");
                    });
    
            Completable completable = Single.zip(request1, request2, (aLong, aLong2) -> aLong).toCompletable();
    
            TestObserver<Void> test = completable.test();
    
            testScheduler.advanceTimeBy(1010, TimeUnit.MILLISECONDS);
    
            test.assertComplete();
    }
    

    You also can use flatMapCompletable instead of doOnSuccess

    @Test
    public void name() throws Exception {
        TestScheduler testScheduler = new TestScheduler();
        Completable request1 = Single.timer(1000, TimeUnit.MILLISECONDS, testScheduler)
                .flatMapCompletable(this::saveToDb);
    
        Completable request2 = Single.timer(500, TimeUnit.MILLISECONDS, testScheduler)
                .flatMapCompletable(this::saveToDb);
    
        // need to cheat here, becuase completeable does not provide zip
        Completable completable = Single.zip(request1.toSingle(() -> 1), request1.toSingle(() -> 1), (aLong, aLong2) -> aLong)
                .toCompletable();
    
        TestObserver<Void> test = completable.test();
    
        testScheduler.advanceTimeBy(1010, TimeUnit.MILLISECONDS);
    
        test.assertComplete();
    }
    
    private Completable saveToDb(long value) {
        return Completable.complete();
    }
    
    0 讨论(0)
提交回复
热议问题