【RxJava】エラー発生時に retryWhen を使ってリトライダイアログを表示する
RxJava でエラーが発生したときに、もう一度リトライするか否かのダイアログを表示できないかと思い、方法を調べてみたときの備忘録。
RxJava ではエラーが発生した場合、例外処理として Subscriber 内の onError メソッドが即座に実行されます。
Observable .create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("test1"); subscriber.onNext("test2"); subscriber.onError(new Throwable("エラーテスト")); // エラーが発生 } }) .subscribe(new Subscriber<String>() { @Override public void onNext(String s) { System.out.println("onNext:" + s); } @Override public void onError(Throwable e) { System.out.println("onError:" + e.getMessage()); // 即座に例外処理が行われる } @Override public void onCompleted() { System.out.println("onCompleted"); } });
実行結果:
onNext:test1 onNext:test2 onError:エラーテスト
この例外処理を行う前にリトライダイアログを挟みたいのですが、そのような場合は retrywhen オペレータを使用するといいようです。
retrywhen はエラーが発生した場合に例外処理よりも前に呼びだされ、本当に例外処理にエラーを流していいのか、それとももう一度リトライするのかを決めることができます。
これを利用し、表題のリトライダイアログを実装してみます。エラーが発生したらダイアログを表示し、「はい」を押したらリトライ、「いいえ」を押したら通常通り例外処理を行います。
Observable .create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("test1"); subscriber.onNext("test2"); subscriber.onError(new Throwable("エラーテスト")); } }) .retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() { @Override public Observable<?> call(final Observable<? extends Throwable> observable) { return observable.flatMap(new Func1<Throwable, Observable<?>>() { @Override public Observable<?> call(Throwable throwable) { return Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { new AlertDialog.Builder(MainActivity.this) .setTitle("エラー") .setMessage("もう一度リトライしますか?") .setPositiveButton("はい", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { subscriber.onNext(null); } }) .setNegativeButton("いいえ", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { subscriber.onError(throwable); } }) .show(); } }); } }); } }) .subscribe(new Subscriber<String>() { @Override public void onNext(String s) { System.out.println("onNext:" + s); } @Override public void onError(Throwable e) { System.out.println("onError:" + e.getMessage()); } @Override public void onCompleted() { System.out.println("onCompleted"); } });
ラムダ式を使用してスッキリさせると
Observable .create(subscriber -> { subscriber.onNext("test1"); subscriber.onNext("test2"); subscriber.onError(new Throwable("エラーテスト")); }) .retryWhen(observable -> observable.flatMap(throwable -> Observable.create(subscriber -> new AlertDialog.Builder(MainActivity.this) .setTitle("エラー") .setMessage("もう一度リトライしますか?") .setPositiveButton("はい", (dialog, which) -> subscriber.onNext(null) ) .setNegativeButton("いいえ", (dialog, which) -> subscriber.onError(throwable) ) .show() ) ) ) .subscribe( onNext -> System.out.println("onNext:" + onNext), onError -> System.out.println("onError:" + onError.getMessage()), () -> System.out.println("onCompleted") );
実行結果:
onNext:test1 onNext:test2 -> はい onNext:test1 onNext:test2 -> はい onNext:test1 onNext:test2 -> いいえ onError:エラーテスト