申明一下,目前对Rx家族还没做过什么研究和学习,目前要学习的东西比较多,暂且也是用Rx多一点点。所以就针对使用上做一个总结,记录一下,后续肯定还是要加强研究的。
(这几天也是搞ViewPaper的轮播,主要是Glide动态加载和回收部分,搞了好几天....后面还打算继续研究,做一个自己需求的轮播(重点想搞下图片加载的优化部分 - 我看有的banner是直接一次性创建多个ImageView以及Glide直接初始化好...我觉得这样内存上会有所损耗,当然具体还得再研究下))
那就开始吧。。。Func1主要是请求获取的数据上做预处理,然后返出去给到Subscriber(具体Rxjava的东西后面研究).
So,我们可以自定义Func1,然后重写其R call(T t);方法。看下这个接口的定义:
public interface Func1<T, R> extends Function {
R call(T t);
}
这是一个泛型定义,T就是获取的数据(入参), R就是需要返给Subscriber的数据,出参。
1.我们在定义Retrofit相关请求方法的时候可以这样:
image也就是内部将会把数据转换为我们需要的类型(字符串或者对象,然后返给我们),所以这里的这个T类型就是上面的String,或者HttpResponse<NewsBean>等...
HttpResponse<NewsBean>这个是什么呢? 直接看:
HttpResponse.java - 后台常规返回的数据类型结构基本都是这样(而这个data就是我们真正需要的json数据对象),这样看要清楚多了。。。。
/*
*@Description: 基础网络数据封装
*@Author: hl
*@Time: 2018/9/27 16:16
*/
public class HttpResponse<T> {
private int code;
private String message;
private String request_time;
private T data;
public HttpResponse(){}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getRequest_time() {
return request_time;
}
public void setRequest_time(String request_time) {
this.request_time = request_time;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
@Override
public String toString() {
return "HttpResponse{" +
"status=" + code +
", msg='" + message + '\'' +
", data=" + data +
", data=" + request_time +
'}';
}
}
现在我们就可以自定义ResponseFunc了。
import rx.functions.Func1;
/*
*@Description: 请求数据封装 - 增加中间处理过程(可以选择处理或者直接返回)
*@Author: hl
*@Time: 2018/9/29 15:38
* W - 表示输入的数据,也就是请求获得的data数据(对象,字符串等格式)
* T - 表示返回的数据,最终到onNext(Ojbect o)
* W输入数据通过回调CallMe.onCall可以进行中间处理过程,然后返回T
*/
public class ResponseFunc<T, W> implements Func1<HttpResponse<W>, T> {
private CallMe<T, W> callMe;
public ResponseFunc(CallMe<T, W> callMe){
this.callMe = callMe;
}
@Override
public T call(HttpResponse<W> tHttpResponse) {
if (0 == tHttpResponse.getCode()) {
///< 成功
return callMe.onCall(tHttpResponse.getData(), tHttpResponse.getRequest_time());
}else if (2 == tHttpResponse.getCode()) {
///< Token过期
throw new ApiException(ApiException.TOKEN);
}else{
///< 其他情况
throw new ApiException(ApiException.ERROR);
}
}
public interface CallMe<T, W>{
public T onCall(W data, String requestTime);
}
}
说明:相当于我拦截了原来的call回调,然后里面进行处理,然后通过自定义的接口回调onCall将真正的数据进行返回...同时还附带了请求时间啥的。可以根据自己的需求进行扩展...
其中像ApiException怎么说了,这里如果我们throw new一个ApiException的话,其结果会返给Subscriber的onError方法。进而我们就可以在自定义的Subscriber中进行异常处理。
到这里相当于就是: Fun1进行了数据预处理, Subscriber进行了异常相关处理
直接看代码:
/*
*@Description: 自定义异常封装
*@Author: hl
*@Time: 2018/9/29 15:38
*/
public class ApiException extends RuntimeException{
public static final int ERROR = 1;
public static final int TOKEN = 2;
public static final int NO_NET = 3;
private static String message;
public ApiException(int resultCode) {
this(getApiExceptionMessage(resultCode));
}
public ApiException(String detailMessage) {
super(detailMessage);
}
@Override
public String getMessage() {
return message;
}
/**
* 由于服务器传递过来的错误信息直接给用户看的话,用户未必能够理解
* 需要根据错误码对错误信息进行一个转换,在显示给用户
* @param code
* @return
*/
private static String getApiExceptionMessage(int code){
switch (code) {
case TOKEN:
message = "Token过期";
break;
case ERROR:
message = "请求错误";
break;
case NO_NET:
message = "网络未连接";
break;
default:
message = "未知错误";
}
return message;
}
}
然后就可以直接看自定义Subscriber - BaseView(MVP模式相关) 可以删除掉先(我本来打算用来吐司啥的...后面可以扩展....)
import rx.Subscriber;
/**
* Created by hl on 2018/7/4.
* 1\. 增加具体错误处理回调 - 给需要使用的地方(比如没有重试处理界面的地方)
*/
public abstract class BaseSubscribers<T> extends Subscriber<T> {
private BaseView baseView;
private BaseSubscribers() {
}
public BaseSubscribers(BaseView baseView) {
this.baseView = baseView;
}
@Override
public void onStart() {
super.onStart();
if (!NetworkUtil.isNetworkConnected(MyApplication.getInstance())) {
///< 取消订阅(后续订阅通知则不再重复发送)
unsubscribe();
///< 发送错误事件(一定要加,因为网络请求可能需要错误处理,比如进度条消失等)
//onError(new Throwable("当前网络不可用!"));
onError(new ApiException(ApiException.NO_NET));
//baseView.showToast("当前网络不可用,请检查网络情况!");
//onCompleted();
}
}
@Override
public void onError(Throwable e) {
if (e instanceof Exception) {
///< 访问获得对应的Exception
onErrors(ExceptionHandle.handleException(e));
} else if (e.getMessage().contains("当前网络不可用")) {
///< 将Throwable 和 网络错误的status code返回
ExceptionHandle.ResponeThrowable responeThrowable = new ExceptionHandle.ResponeThrowable(e, ExceptionHandle.ERROR.NO_NETWORK);
responeThrowable.message = e.getMessage();
onErrors(responeThrowable);
} else {
///< 将Throwable 和 未知错误的status code返回
ExceptionHandle.ResponeThrowable responeThrowable = new ExceptionHandle.ResponeThrowable(e, ExceptionHandle.ERROR.UNKNOWN);
responeThrowable.message = e.getMessage();
onErrors(responeThrowable);
}
}
public abstract void onErrors(ExceptionHandle.ResponeThrowable responeThrowable);
}
说明:其实也是相当于拦截了onError,然后自定义onErrors进行错误回调处理。和Fun1一样的玩法...
其中ExceptionHandle是错误类型的相关处理,可以根据需要扩展:
import android.util.Log;
import com.google.gson.JsonParseException;
import org.json.JSONException;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import retrofit2.HttpException;
/**
* 错误异常处理类
* 1.Retrifit网络错误回调,有时候需要做提示
*/
public class ExceptionHandle {
private static final int UNAUTHORIZED = 401;
private static final int FORBIDDEN = 403;
private static final int NOT_FOUND = 404;
private static final int REQUEST_TIMEOUT = 408;
private static final int INTERNAL_SERVER_ERROR = 500;
private static final int BAD_GATEWAY = 502;
private static final int SERVICE_UNAVAILABLE = 503;
private static final int GATEWAY_TIMEOUT = 504;
public static ResponeThrowable handleException(Throwable e) {
ResponeThrowable ex;
Log.e("tag", "e.toString = " + e.toString());
if (e instanceof HttpException) {
HttpException httpException = (HttpException) e;
ex = new ResponeThrowable(e, ERROR.HTTP_ERROR);
switch (httpException.code()) {
case UNAUTHORIZED:
case FORBIDDEN:
case NOT_FOUND:
case REQUEST_TIMEOUT:
case GATEWAY_TIMEOUT:
case INTERNAL_SERVER_ERROR:
case BAD_GATEWAY:
case SERVICE_UNAVAILABLE:
default:
//ex.code = httpException.code();
ex.message = "连接错误";
break;
}
return ex;
} else if (e instanceof ServerException) {
ServerException resultException = (ServerException) e;
ex = new ResponeThrowable(resultException, resultException.code);
ex.message = resultException.message;
return ex;
} else if (e instanceof JsonParseException
|| e instanceof JSONException
/*|| e instanceof ParseException*/) {
ex = new ResponeThrowable(e, ERROR.PARSE_ERROR);
ex.message = "解析错误";
return ex;
} else if (e instanceof ConnectException) {
ex = new ResponeThrowable(e, ERROR.NETWORK_ERROR);
ex.message = "连接失败";
return ex;
} else if (e instanceof javax.net.ssl.SSLHandshakeException) {
ex = new ResponeThrowable(e, ERROR.SSL_ERROR);
ex.message = "证书验证失败";
return ex;
}else if (e instanceof ApiException){
if (e.getMessage().contains("Token")){
ex = new ResponeThrowable(e, ERROR.TOKEN);
}else if (e.getMessage().contains("网络未连接")){
ex = new ResponeThrowable(e, ERROR.NO_NETWORK);
}else{
ex = new ResponeThrowable(e, ERROR.UNKNOWN);
}
ex.message = e.getMessage();
return ex;
}else if (e instanceof SocketTimeoutException){
ex = new ResponeThrowable(e, ERROR.SOCKET_TIMEOUT_ERROR);
ex.message = "请求超时";
return ex;
}
else if (e instanceof UnknownHostException){
ex = new ResponeThrowable(e, ERROR.SOCKET_TIMEOUT_ERROR);
ex.message = "无法连接服务器";
return ex;
}
else {
ex = new ResponeThrowable(e, ERROR.UNKNOWN);
ex.message = e.getMessage();
return ex;
}
}
/**
* 约定异常
*/
public class ERROR {
/**
* 网络错误
*/
public static final int NO_NETWORK = 999;
/**
* 未知错误
*/
public static final int UNKNOWN = 1000;
/**
* 解析错误
*/
public static final int PARSE_ERROR = 1001;
/**
* 网络错误
*/
public static final int NETWORK_ERROR = 1002;
/**
* 协议出错
*/
public static final int HTTP_ERROR = 1003;
/**
* 证书出错
*/
public static final int SSL_ERROR = 1005;
/**
* Socket超时
*/
public static final int SOCKET_TIMEOUT_ERROR = 10060;
/**
* TOKEN过期
*/
public static final int TOKEN = 110110;
}
public static class ResponeThrowable extends Exception {
public int code;
public String message;
public ResponeThrowable(Throwable throwable, int code) {
super(throwable);
this.code = code;
}
}
/**
* ServerException发生后,将自动转换为ResponeThrowable返回
*/
class ServerException extends RuntimeException {
int code;
String message;
}
}
到此,我们整个自定义Func1和Subscriber就完事了。目前经过一段时间运行,问题不大...性能也没啥特别影响。后续研究的比较明白了,可以再扩展和完善。
用法简单走一走:
imageSubscription subscription = informationService.getCategoryNew(hashMap). ///< getCategory
subscribeOn(Schedulers.io())
//.timeout() ///< 这个地方不要设置超时处理,多次调用会闪退,正确的用法是自定义okhttp3去设置超时
.map(new ResponseFunc<NewsBean, NewsBean>(new ResponseFunc.CallMe<NewsBean, NewsBean>() {
@Override
public NewsBean onCall(NewsBean data, String requestTime) {
return data;
}
}))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BaseSubscribers<NewsBean>(view) {
@Override
public void onCompleted() {
///< 如果是刷新才调用刷新结束接口
if (bIsRefresh) {
if (1 == page) {
view.finishRefresh();
} else {
view.finishLoadMore();
}
}
}
@Override
public void onErrors(ExceptionHandle.ResponeThrowable responeThrowable) {
///< 接下来就可以根据状态码进行处理...
int statusCode = responeThrowable.code;
switch (statusCode) {
case ExceptionHandle.ERROR.TOKEN:
UserInfoControlPresenter.clearAcount();
view.showToast("你的账号异常,请重新登录,谢谢!");
break;
default:
view.showToast(responeThrowable.message);
break;
}
///< 不是刷新,比如首次加载失败或者重试也失败,则显示点击重试界面
if (!bIsRefresh) {
view.retryDialog();
} else {
view.onRequestFailer();
}
onCompleted();
}
@Override
public void onNext(NewsBean o) {
if (null == o) {
//view.showToast("发生了点小意外!");
if (!bIsRefresh) {
view.retryDialog();
}
} else if (null != o.getPosts() && o.getPosts().size() < 1) {
view.showToast("我们正努力为您编辑更多资讯!");
if (!bIsRefresh) {
view.disDialog();
} else {
view.onRequestFailer();
}
} else {
if (1 == page) {
view.resetItemList();
view.addNewsItemList(o);
} else {
view.addNewsItemList(o);
}
if (!bIsRefresh) {
view.disDialog();
}
}
}
});
什么不精简,封装不太好等,小白都清楚,毕竟小白的起步封装。后面还会继续学习研究,将对刷新和不刷新做通用的网络请求和处理....相信就不用那么多的presenter了。。。
简单记录下。。顺便给自己回忆的理由....爱爱哎!
网友评论