我最近在玩Rxjava尝试实现一系列事件(Api callas /数据库操作),并且在处理错误时似乎遇到了障碍。
这就是我想要做的。我正在调用Api来检查数据库中是否存在用户。基于我得到的响应,我试图使用rxjava链接一些序列。下图可能会解释得更好。
checkUser()
/ \
No Yes
/ \
createUserRemote() FetchUserNotesRemote()
| |
End SaveUserNotesLocal()
|
End
我能够将checkUser() - >链接在一起FetchUserNotesRemote() - > SaveUserNotesLocal()序列,包含以下代码。
checkUser()
.flatMap(id -> {return fetchData(id);})
.flatMap(notesResponseObject -> {return saveFetchedData(notesResponseObject);})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<Integer>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onSuccess(Integer integer) {
//handle onsuccess here
}
@Override
public void onError(Throwable e) {
//handle errors here
}
});
我主要试图解决的问题。
答案 0 :(得分:6)
1)要在出错时执行不同的可观察链,可以使用方法onErorrResumeNext()
。更多信息:github.com/ReactiveX/RxJava/wiki/Error-Handling-Operators
示例:
checkUser().flatMap(id -> {return fetchData(id);})
.flatMap(notesResponseObject -> {return saveFetchedData(notesResponseObject);})
.onErrorResumeNext(throwable -> { return doSomethingDifferent(); }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<Integer>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onSuccess(Integer integer) {
//handle onsuccess here
}
@Override
public void onError(Throwable e) {
//handle errors here
}
});
2)如果在流中的某处抛出异常,则会将其传递给订阅者onError()
。如果您想知道抛出流错误的哪个部分,可以添加多个onErorrResumeNext()
调用,这些调用会在每次api调用后抛出具体异常。
checkUser()
.onErrorResumeNext(throwable -> { return Observable.error(new CheckUserException()); }
.flatMap(id -> {return fetchData(id);})
.onErrorResumeNext(throwable -> { return Observable.error(new FetchDataException()); }
.flatMap(notesResponseObject -> {return saveFetchedData(notesResponseObject);})
.onErrorResumeNext(throwable -> { return Observable.error(new SaveDataException()); }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<Integer>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onSuccess(Integer integer) {
//handle onsuccess here
}
@Override
public void onError(Throwable e) {
//handle errors here
}
});
答案 1 :(得分:0)
我完全忘记了这一点。但是@mol将我推向正确的方向。我的解决方案有些不同。这可能不是最佳解决方案,但当时对我有用。
我首先创建了自己的自定义异常类,如下所示。
public class CreateUserLocalException extends Exception {
public CreateUserLocalException(String message) {
super(message);
}
}
然后在我的checkUser()函数中,抛出上面创建的类型异常,如下所示。
public Single<String> checkUser(String id) {
return Single.create(new SingleOnSubscribe<String>() {
@Override
public void subscribe(SingleEmitter<String> emitter) throws Exception {
try {
GetUserResponseObject getUserResponseObject = apiClient.usersIdGet(id);
Log.d("Test", "checkUserCall: Status: " + getUserResponseObject.getStatus());
emitter.onSuccess(getUserResponseObject.getBody().getUserId());
} catch (AmazonServiceException e) {
Log.d("Test", "AmazonServiceException : " + e.getErrorMessage());
e.printStackTrace();
if (e.getErrorMessage().equals("timeout")) {
throw new SocketTimeoutException();
} else {
throw new CheckUserException(Integer.toString(e.getStatusCode()));
}
} catch (Exception e) {
e.printStackTrace();
throw new CheckUserException(Integer.toString(AppConstants.ERROR));
}
}
});
}
然后在我的调用链中,如果发生错误,则在我检查Exception实例以识别发生哪种异常的地方调用onError(throwable)。下面是功能链的代码。
cloudSyncHelper.checkUser(user.getUser_id())
.retry(3, new Predicate<Throwable>() {
@Override
public boolean test(Throwable throwable) throws Exception {
Log.d("Test", throwable.toString());
if (throwable instanceof SocketTimeoutException) {
Log.d("Test", "Time out.. Retrying..");
return true;
}
return false;
}
})
.flatMap(s -> {
return cloudSyncHelper.createUserLocal(user)
.onErrorResumeNext(throwable -> {
Log.d("Test", "onErrorResumeNext, throwable message: " + throwable.getMessage());
if (throwable instanceof CreateUserLocalException) {
if (Integer.parseInt(throwable.getMessage()) == AppConstants.LOCAL_DB_DUPLICATE) {
return Single.just(user.getUser_id());
}
}
return Single.error(new CreateUserLocalException(Integer.toString(AppConstants.LOCAL_DB_ERROR)));
});
})
.flatMap(id -> {
return cloudSyncHelper.fetchData(id)
.retry(3, new Predicate<Throwable>() {
@Override
public boolean test(Throwable throwable) throws Exception {
Log.d("Test", throwable.toString());
if (throwable instanceof SocketTimeoutException) {
Log.d("Test", "Time out.. Retrying..");
return true;
}
return false;
}
});
})
.flatMap(notesResponseObject -> {
return cloudSyncHelper.saveFetchedData(notesResponseObject);
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<Integer>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onSuccess(Integer integer) {
//handle onsuccess here
googleSignInButton.setEnabled(true);
progressBar.setVisibility(View.GONE);
Log.d("Test", "onSuccess Called");
getSharedPreferences(AppConstants.AppName, MODE_PRIVATE).edit().putBoolean("isFirstRun", false).apply();
startActivity(new Intent(LoginScreen.this, HomeScreen.class));
}
@Override
public void onError(Throwable e) {
if (e instanceof SocketTimeoutException) {
googleSignInButton.setEnabled(true);
progressBar.setVisibility(View.GONE);
Log.d("Test", "Socket Time Out");
Utils.createToast(LoginScreen.this, "Socket timed out");
return;
}
int code = Integer.parseInt(e.getMessage());
Log.d("Test", "onError Called");
if (e instanceof CheckUserException) {
Log.d("Test", "onError CheckUserException");
if (code == AppConstants.NOTFOUND) {
newUserSequence(user);
} else {
googleSignInButton.setEnabled(true);
progressBar.setVisibility(View.GONE);
Utils.createToast(LoginScreen.this, "Unable to user information from cloud. Try again.");
}
}
if (e instanceof CreateUserLocalException) {
Log.d("Test", "onError CreateUserLocalException");
googleSignInButton.setEnabled(true);
progressBar.setVisibility(View.GONE);
}
if (e instanceof FetchDataException) {
Log.d("Test", "onError FetchDataException");
if (code == AppConstants.NOTFOUND) {
googleSignInButton.setEnabled(true);
progressBar.setVisibility(View.GONE);
getSharedPreferences(AppConstants.AppName, MODE_PRIVATE).edit().putBoolean("isFirstRun", false).apply();
startActivity(new Intent(LoginScreen.this, HomeScreen.class));
} else {
googleSignInButton.setEnabled(true);
progressBar.setVisibility(View.GONE);
Log.d("Test", "Unable to fetch data from cloud");
Utils.createToast(LoginScreen.this, "Unable to fetch data from cloud. Try again.");
}
}
if (e instanceof SaveDataLocalException) {
googleSignInButton.setEnabled(true);
progressBar.setVisibility(View.GONE);
Log.d("Test", "onError SaveDataLocalException");
if (code == AppConstants.LOCAL_DB_ERROR) {
Log.d("Test", "Unable to save data fetched from cloud");
Utils.createToast(LoginScreen.this, "Unable to save data fetched from cloud");
} else {
Utils.createToast(LoginScreen.this, "Unable to save data fetched from cloud");
}
}
}
});
希望这会有所帮助。