Первый подход, который я упомянул в комментарии, следующий:
создайте класс держателя для результата
class ToDoResult {
boolean isCached;
String todo;
Throwable error; // this will be set only in case of error
public ToDoResult(String todo, boolean isCached) {
this.isCached = isCached;
this.todo = todo;
}
public void setError(Throwable error) {
this.error = error;
}
}
Затем сделайте ваш fetchTodo () возвратным Single<ToDoResult>
вместо Single<String>
следующим образом
public class GetTodoRepository {
public Single<ToDoResult> fetchTodo() {
return retrofit.create(TodoApi.class)
.getTodo()
.doOnSuccess(s -> cacheManager.saveTodo(s))
.map(todo -> new ToDoResult(todo,false))
.onErrorReturn(throwable -> {
ToDoResult toDoResult = new ToDoResult(cacheManager.getTodo(), true);
toDoResult.setError(throwable);
return toDoResult;
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
}
А у вас ViewModel
getTodoRepository.fetchTodo().subscribe(new SingleObserver<ToDoResult>() {
@Override
public void onSuccess(ToDoResult toDoResult) {
showProgressAnim.setValue(false);
if (toDoResult.error != null) {
errorMsg.setValue(toDoResult.error.getMessage());
} else {
todo.setValue(toDoResult.todo);
}
}
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onError(Throwable e) {
showProgressAnim.setValue(false);
errorMsg.setValue(e.getMessage());
}
});
При таком подходе ваш onError
никогда не будет вызван, поскольку мы всегда преобразуем ошибку в сигнал успеха.
Второй подход согласно @akarnokd, упомянутому в предыдущем ответе, заключается в использовании Observable и запуске onNext
и onError
спина к спине.
public class GetTodoRepository {
public Observable<String> fetchTodo() {
return retrofit.create(TodoApi.class)
.getTodo()
.doOnSuccess(s -> cacheManager.saveTodo(s))
.toObservable()
.onErrorResumeNext(error ->
Observable.just(cached)
.concatWith(Observable.error(error))
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
}
И измените свою модель вида следующим образом
getTodoRepository.fetchTodo().subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
// this will be triggered with the todo item (cached in case of error)
}
@Override
public void onError(Throwable e) {
// this will be triggered followed by onNext in case of error
}
@Override
public void onComplete() {
}
});