In the actual project (Retrofit+RxJava framework), sometimes we need to log in first, obtain the token and then obtain the user information, so we need to filter the information returned by the server after login to get the token we need, and then obtain the user information according to the token. What we ultimately need to do is transform the data stream.
In RxJava, there are many operators that can transform a data flow. Here we use the FlatMap transform operator to do so.
In the RESTResult object, which contains the status of the request return: failure or success, error code, User object, etc., we first define a Response entity class that returns data based on the interface:
public class Response<T> extends Entity {
public boolean isSuccess() {
return infoCode == 1;
}
public boolean isTokenExpired() {
return infoCode == -1;
}
public int infoCode;
public String message;
public int size;
public T data;
}
Copy the code
Logic processing:
- Login failure, directly trigger onError;
- Login succeeds, according to the obtained token request user information interface final call subscribe onNext event;
The following code looks like this:
private void login(final String phone , final String password){ APIWrapper.getInstance().login(phone, password) .flatMap(new Func1<Response<TokenEntity>, Observable<Response<UserInfo>>>() { @Override public Observable<Response<UserInfo>> call(Response<TokenEntity> response) { if (response.isSuccess()) { TokenEntity tokenEntity = response.data; return APIWrapper.getInstance().getUserInfo(tokenEntity.token); } else { return Observable.error(new ApiException(response.message)); } } }) .compose(new RxHelper<Response<UserInfo>>(getString(R.string.wait_to_login_tip)).io_main(LoginActivity.this)) .subscribe(new RxSubscriber<Response<UserInfo>>(this,USER_LOGIN) { @Override public void _onNext(Response<UserInfo> response) { if (response.isSuccess()) { UserInfo userInfo = response.data; if (null ! = userInfo) { AppApplication.getInstance().saveUserInfo(userInfo); } finish(); } } @Override public void _onError(String msg) { ToastUtils.show(LoginActivity.this, msg); }}); }Copy the code
According to the above code, the handling of the login failure is critical:
if (response.isSuccess()) {
TokenEntity tokenEntity = response.data;
return APIWrapper.getInstance().getUserInfo(tokenEntity.token);
} else {
return Observable.error(new ApiException(response.message));
Copy the code
No matter what causes the login failure, should be prompted with the user.
ApiException code:
public class ApiException extends RuntimeException { public static final int USER_NOT_EXIST = 100; public static final int WRONG_PASSWORD = 101; public static final int ERROR = 2001; public ApiException(int resultCode) { this(getApiExceptionMessage(resultCode)); } public ApiException(String detailMessage) { super(detailMessage); } /** * The server sends error messages directly to the user, the user may not be able to understand * need to convert error messages according to the error code, @param Code * @return */ private static String getApiExceptionMessage(int Code){String Message; Switch (code) {case USER_NOT_EXIST: message = "this user does not exist "; break; Case WRONG_PASSWORD: message = "Password error "; break; Default: message = "unknown error "; } return message; }}Copy the code
With RxJava’s chaining operations and the right operators, you can transmit not only normal data sources to the observer, but also error exception data sources to the observer. RxJava is much more powerful than you think!
More reference: Retrofit+RxJava elegant handling server return exceptions, errors