学习了一段时间Rxjava2、Retrofit2,为了以后项目能直接用,决定自己手动封装一下,虽然网上也有不少Demo,但是为了加深印象,还是根据自己的理解简单的封装一下。
文章中涉及到的Rxjava2、Retrofit2基础知识就不再多说,大家自行google即可。
首先写一个mHttpRequest ,作为网络请求接口
public interface mHttpRequest {
//参数很简单,可能有人会疑惑,为啥需要传clazz,后面会提到
void request(String url, Class clazz, mCallBack callBack);
void request(String url, HttpParameter param, mCallBack callBack);
}
//===================================
public class HttpRequestFactory {
private static mHttpRequest mHttpRequest;
public static mHttpRequest getRetrofitHttpRequest() {
if (mHttpRequest == null) {
synchronized (HttpRequestFactory.class) {
if (mHttpRequest == null) {
mHttpRequest = new retrofitHttpRequest();
}
}
}
return mHttpRequest;
}
}
同时用工厂模式将,网络请求类的对象返回。
这里实例化了一个retrofitHttpRequest类,作为retrofit的请求。这样写的好处也就是如果以后需要更换网络请求框架,直接在HttpRequestFactory里写一个 getXXXXHttpRequest方法即可,不用到每个网络请求的地方去改。
接下来就需要实现我们的retrofitHttpRequest请求类,实现刚刚的mHttpRequest即可。首先得到retrofit、及API的对象。
public static void init() {
if (retrofit == null) {
// 指定缓存路径,缓存大小100Mb
Cache cache = new Cache(new File(mApplication.getmContext().getCacheDir(), "HttpCache"),
1024 * 1024 * 100);
OkHttpClient client = new OkHttpClient.Builder().cache(cache)
.connectTimeout(3, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build();
retrofit = new Retrofit.Builder()
.client(client)
.baseUrl(BASE_URL)
.addConverterFactory
(GsonConverterFactory.create())
.addCallAdapterFactory
(RxJava2CallAdapterFactory.create())
.build();
api = retrofit.create(RetrofitApi.class);
}
}
//这里是API类
public interface RetrofitApi {
//由于我这里服务器需要json数据,所以用@Body来传参
@POST
Observable getResponse(@Url String url, @Body Map parameter);
//这里踩坑记录:retrofit不支持:type泛型
@POST
Observable getResponse(@Url String url);
}
这里不多说,接下来就是我们的重点,网络请求的方法
@Override
public void request(String url, final HttpParameter param, final mCallBack callBack) {
api.getResponse(url, param.getParameters())
.map(new Function() {
@SuppressWarnings("unchecked")
@Override
public T apply(HttpResult tHttpResult) throws Exception {
if (tHttpResult.isStatus()) {
//这里因为api里没有填泛型导致返回的数据不是bean,所以用gson转换一下,这里也就是为什么需要用到clazz对象的原因。
//大家如果有更好的方案可以留言告诉我
return (T) new Gson().fromJson(tHttpResult.getData().toString(), param.getClazz());
} else {
throw new Exception(tHttpResult.getMessage());
}
}
})
// 获取异常并进行判断,优雅的返回
.onErrorResumeNext(new RxjavaFactory.HttpResponseFunc())
.compose(RxjavaFactory.io_main_trasformer())
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
Log.e("retrofitHttpRequest", "onSubscribe: ");
}
@Override
public void onNext(T value) {
if (value != null)
callBack.success(value);
}
@Override
public void onError(Throwable e) {
callBack.fail(e.getMessage());
Log.e("retrofitHttpRequest", "onError: " + e.getMessage());
}
@Override
public void onComplete() {
Log.e("retrofitHttpRequest", "onComplete: ");
}
});
}
整个流程也非常简单,至于
onErrorResumeNext(new RxjavaFactory.HttpResponseFunc<T>())
是为了优雅的返回服务器或其他未知的异常,HttpResponseFunc的代码如下:
public static class HttpResponseFunc<T> implements Function<Throwable, Observable<T>> {
@Override
public Observable apply(Throwable throwable) throws Exception {
return Observable.error(ExceptionUtils.handleException(throwable));
}
}
如果产生异常,onErrorResumeNext操作符会处理异常信息,并将我们自定义的message返回到onError里:
@Override
public void onError(Throwable e) {
callBack.fail(e.getMessage());
Log.e("retrofitHttpRequest", "onError: " + e.getMessage());
}
下面是我们处理异常信息的工具类:
public class ExceptionUtils {
//对应HTTP的状态码
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 Exception handleException(Throwable e) {
String ex;
if (e instanceof HttpException) { //HTTP错误
HttpException httpException = (HttpException) e;
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 = "网络出错了"; //均视为网络错误
break;
}
} else if (e instanceof JsonParseException
|| e instanceof JSONException
|| e instanceof ParseException) {
ex = "数据解析错误"; //均视为解析错误
} else if (e instanceof ConnectException) {
ex = "网络连接失败"; //均视为网络错误
} else {
ex = e.getMessage(); //未知错误或服务器返回
}
return new Exception(ex);
}
}
这样我们就能返回对应异常信息,对于用户和我们自己开发都有便利。
对于RXjava优雅的返回异常信息,还不理解的可以戳这里。
这样整个封装就完成了,是不是很简(la)单(ji)。
使用起来也很简单,只需要实现参数类:
public class HttpParameter {
public Map parameters;
public Class clazz;
public Class getClazz() {
return clazz;
}
public void setClazz(Class clazz) {
this.clazz = clazz;
}
public HttpParameter() {
parameters = new HashMap<>();
}
public Map getParameters() {
return parameters;
}
public void addParameter(String key,String parameter){
parameters.put(key,parameter);
}
}
用法:
HttpParameter parameter = new HttpParameter();
parameter.addParameter("phone", userName);
parameter.addParameter
("psw",ciPherUtils.Str2MD5LowCase(password));
parameter.setClazz(UserLoginBean.class);
HttpRequestFactory.getRetrofitHttpRequest().request
(loginUrl, parameter, new mCallBack() {
@Override
public void success(UserLoginBean response) {
//todo something
}
@Override
public void fail(String message) {
//message为异常信息哦
}
});
由于能力原因,可能有部分不足之处,希望大家指出,共同进步。
想要源码的在这里:https://github.com/mrqatom/atomRXDT-MVP
这是一个retrofit2+rxjava2+dagger2+mvp+test+greenDao3的项目,非常适合入门,如果有兴趣也可以star一下哦~
目前完成了登录功能,由于是工作之余来写的,所以功能暂时不全,但是我会一直更新,因为实战才能真正提高嘛。