java call user func_Android-Retrofit2+Rxjava2之网络请求预处理-Func1、Subscriber

申明一下,目前对Rx家族还没做过什么研究和学习,目前要学习的东西比较多,暂且也是用Rx多一点点。所以就针对使用上做一个总结,记录一下,后续肯定还是要加强研究的。

(这几天也是搞ViewPaper的轮播,主要是Glide动态加载和回收部分,搞了好几天....后面还打算继续研究,做一个自己需求的轮播(重点想搞下图片加载的优化部分 - 我看有的banner是直接一次性创建多个ImageView以及Glide直接初始化好...我觉得这样内存上会有所损耗,当然具体还得再研究下))

那就开始吧。。。Func1主要是请求获取的数据上做预处理,然后返出去给到Subscriber(具体Rxjava的东西后面研究).

So,我们可以自定义Func1,然后重写其R call(T t);方法。看下这个接口的定义:

public interface Func1 extends Function {

R call(T t);

}

这是一个泛型定义,T就是获取的数据(入参), R就是需要返给Subscriber的数据,出参。

1.我们在定义Retrofit相关请求方法的时候可以这样:

cfa8941e2154

image

也就是内部将会把数据转换为我们需要的类型(字符串或者对象,然后返给我们),所以这里的这个T类型就是上面的String,或者HttpResponse等...

HttpResponse这个是什么呢? 直接看:

HttpResponse.java - 后台常规返回的数据类型结构基本都是这样(而这个data就是我们真正需要的json数据对象),这样看要清楚多了。。。。

/*

*@Description: 基础网络数据封装

*@Author: hl

*@Time: 2018/9/27 16:16

*/

public class HttpResponse {

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 implements Func1, T> {

private CallMe callMe;

public ResponseFunc(CallMe callMe){

this.callMe = callMe;

}

@Override

public T call(HttpResponse 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{

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 extends Subscriber {

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就完事了。目前经过一段时间运行,问题不大...性能也没啥特别影响。后续研究的比较明白了,可以再扩展和完善。

用法简单走一走:

cfa8941e2154

image

Subscription subscription = informationService.getCategoryNew(hashMap). ///< getCategory

subscribeOn(Schedulers.io())

//.timeout() ///< 这个地方不要设置超时处理,多次调用会闪退,正确的用法是自定义okhttp3去设置超时

.map(new ResponseFunc(new ResponseFunc.CallMe() {

@Override

public NewsBean onCall(NewsBean data, String requestTime) {

return data;

}

}))

.observeOn(AndroidSchedulers.mainThread())

.subscribe(new BaseSubscribers(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了。。。

简单记录下。。顺便给自己回忆的理由....爱爱哎!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值