web-dev-qa-db-ja.com

レトロフィットとRxJavaの複数のリクエストが完了しました

私はする必要があります:

  1. 異なるウェブサイトからのニュースの2つのリストをリクエストする
  2. リクエストの結果を組み合わせる
  3. 日付順に並べ替え
  4. 最新のニュースを10件入手する
  5. 彼らを助けろ
  6. メッセージ全体を表示

たとえば、次の2つのオブザーバブルがあります。

Observable<RegionalNews> regionalNews;
Observable<NationalNews> nationalNews;

public interface NewsNationalService {
  @GET("news/national")
  Observable<News> getNationalNews();
}

public interface NewsRegionalService {
  @GET("news/regional")
  Observable<News> getRegionalNews();
}

組み合わせた結果で特定のことを実行したくない場合は、merge()で十分です。

Observable<RegionalNews> regionalNews = ...;
Observable<NationalNews> nationalNews = ...;

Observable
.merge(regionalNews, nationalNews)
.ignoreElements()
.observeOn(AndroidSchedulers.mainThread())
.doOnComplete(() -> { /* show alert */ })
.subscribe()
6

Zip演算子を使用して、2つのリクエストを非同期で呼び出し、応答時にそれらのデータを保存または処理できます。

例えば。

以下は2つのObservableです

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

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

上の2つのZipObservable演算子を使用すると、次のようになります。

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() );
        }
    });
9
Priyank Patel

ええと、いつものように異なります。戻り値をチェーンで処理する必要がありますか、それとも単に保存する必要がありますか?

この実装では、SingleとCompletableを使用します。コンプリータブルをサブスクライブすると、両方のシングルが終了すると通知が届きます。

@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();
}

DoOnSuccessの代わりにflatMapCompletableを使用することもできます

@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();
}
4
Hans Wurst

Zipobservablesを組み合わせる方法です。結果を組み合わせることは単なる結果です。

両方のオブザーバブルが完了する(完了する)まで待機する場合、最も簡単な方法はZipを使用することです。リクエストの結果を結合関数で使用する必要はありません。これらの両方の呼び出しが終了したときに別の何かを出力する方法として、この関数を使用してください。この関数がアイテムを発行するとき:

[...]すべてのリクエストが完了したときに何かを実行します(たとえば、アラートを表示します)

たとえば、次のようにします(これらの要求が両方とも完了したときにsomeOtherCallを実行します):

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(...);
3
Bartek Lipinski