본 포스팅은 RxJavaを使ったAndroidにおけるエラーハンドリング 포스팅을 번역했습니다.
제 일본어 실력으로 인하여 오역이나 오타가 발생할 수 있습니다.
실제 발표내용에 해당하는 슬라이드와 슬라이드의 일본어 부분만 번역
만 번역했다는 점 양해바랍니다.
RxJava Advent Calendar 2016 17일째입니다.
여러분, RxJava 사용하고 있습니까? 개인적으로도 일에서도 적극적으로 사용하고 있습니다.
이 문서에서는 RxJava를 사용한 Android의 오류 처리에 대해 쓰고 있습니다.
덧붙여서 나는 “Error Handing in RxJava”라는 제목으로 DroidKaigi 2017에 등장합니다.
이 기사는 발표 예정의 내용을 대략 정리한 것입니다.
RxJava에는 몇 가지 오류 처리용으로 다음과 같은 Operator가 정의되어 있습니다.
이것은 스트림에서 던져진 Exceptioin를 받기 위한 Operator입니다.
Observable observable = Observable.just(0);
observable
.map(new Func1() {
@Override
public Object call(Object o) {
throw new RuntimeException();
}
})
.subscribe(new Subscriber() {
@Override
public void onCompleted() {}
@Override
public void onError(Throwable e) {}
@Override
public void onNext(Object o) {}
});
map에서 throw된 Exception이 onError에 넘어옵니다.
이것은 Exception이 던져진 경우에 대신할 데이터를 흐르게 하기 위한 Operator입니다.
Observable<Integer> observable = Observable.just(0);
observable
.map(new Func1<Integer, Integer>() {
@Override
public Integer call(Integer integer) {
throw new RuntimeException();
}
})
.onErrorReturn(new Func1<Throwable, Integer>() {
@Override
public Integer call(Throwable throwable) {
return 10;
}
})
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {}
});
map에서 Exception이 throw 되면 onErrorReturn가 호출되어 대신할 데이터로 “10”이 반환됩니다.
이것은 Exception이 던져진 경우에 대신 스트림을 흐르게 하기 위한 Operator입니다.
Observable<Integer> observable = Observable.just(0);
observable
.map(new Func1<Integer, Integer>() {
@Override
public Integer call(Integer integer) {
throw new RuntimeException();
}
})
.onErrorResumeNext(new Func1<Throwable, Observable<? extends Integer>>() {
@Override
public Observable<? extends Integer> call(Throwable throwable) {
return Observable.just(0);
}
})
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {}
});
map에서 Exception이 throw 되면 onErrorResumeNext가 호출되어 대신할 스트림으로 “Observable.just(0)”이 반환됩니다.
이것은 Exception이 던져진 경우에 재시도하기 위한 Operator입니다.
Observable<Integer> observable = Observable.just(0);
observable
.map(new Func1<Integer, Integer>() {
@Override
public Integer call(Integer integer) {
throw new RuntimeException();
}
})
.retry()
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {}
});
map에서 Exception이 throw 되면 일반적으로는 스트림이 종료되지만, retry를 작성하는 것으로 다시 subscribe됩니다.
위의 코드는 무한 재시도되지만, 재시도 횟수를 설정할 수 있으며, 일반적으로 재시도 제한을 설정하는 것이 좋습니다.
retryWhen은 조금 이해하기 어렵지만, 재시도할 트리거가되는 스트림을 돌려주기 위한 Operator입니다.
retry의 경우 Exception이 던져진 순간에 재시도가 실행되지만, retryWhen을 사용하여 10초 정도 기다린 후 다시 시도하겠다는 식으로 재시도 타이밍을 세밀하게 제어할 수 있습니다. 10초 정도 기다린 후 다시 시도하는 코드는 다음과 같다.
Observable<Integer> observable = Observable.just(0);
observable
.map(new Func1<Integer, Integer>() {
@Override
public Integer call(Integer integer) {
throw new RuntimeException();
}
})
.retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() {
@Override
public Observable<?> call(Observable<? extends Throwable> observable) {
return observable.flatMap(new Func1<Throwable, Observable<?>>() {
@Override
public Observable<?> call(Throwable throwable) {
return Observable.timer(10, TimeUnit.SECONDS);
}
});
}
})
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {}
});
Android 어플리케이션에서는 다음과 같은 오류 핸들링이 자주 사용되고 있습니다. 이를 RxJava를 사용하여 구현하려 합니다.
이것은 간단하네요. onError에서 Toast를 표시할 뿐입니다.
Observable observable = Observable.just(0);
observable
.map(new Func1() {
@Override
public Object call(Object o) {
throw new RuntimeException();
}
})
.subscribe(new Subscriber() {
@Override
public void onCompleted() {}
@Override
public void onError(Throwable e) {
Toast.makeText(getApplicationContext(), "Error", Toast.LENGTH_SHORT).show();
}
@Override
public void onNext(Object o) {}
});
이것은 조금 전 소개한 retryWhen을 사용합니다. retryWhen에서 Snackbar를 사용하여 사용자 재시도 여부를 묻습니다.
Observable<Integer> observable = Observable.just(0);
observable
.map(new Func1<Integer, Integer>() {
@Override
public Integer call(Integer integer) {
throw new RuntimeException();
}
})
.retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() {
@Override
public Observable<?> call(Observable<? extends Throwable> observable) {
return observable.flatMap(new Func1<Throwable, Observable<?>>() {
@Override
public Observable<?> call(Throwable throwable) {
return Observable.create(new Observable.OnSubscribe<Void>() {
@Override
public void call(final Subscriber<? super Void> subscriber) {
Snackbar snackbar = Snackbar.make(view, "Retry?", Snackbar.LENGTH_INDEFINITE);
snackbar.setAction("Yes", new View.OnClickListener() {
@Override
public void onClick(View view) {
subscriber.onNext(null);
}
});
snackbar.show();
}
});
}
});
}
})
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {}
});
이번에는 다음과 같은 오류 핸들링용 Operator를 소개했습니다.
위의 Operator를 고려하여 Android에서 자주 있는 오류 처리의 구현 예를 소개했습니다.
이 외에도 코멘트를 받을 수 있으면 구현 예를 추가하고 싶습니다.
그럼 좋은 RxJava 라이프를!
comments powered by Disqus
Subscribe to this blog via RSS.