近些年很火的Retrofit+RxJava+OkHttp网络请求框架,功能强大,结构合理,使用简单方便。后面还会给大家发自己整理过的Retrofit和RxJava、RxAndroid和RxBus。希望大家点一下关注,让我这个懒癌患者有动力继续写下去!
本篇分三个部分:基础篇、封装篇和自己项目使用篇,项目是自己公司的APP提取的,文章偏长可以分三部分一点点看,当初看了很多优秀的文章然后自己在整理写在印象笔记中,可惜当初没记下借鉴过的文章地址,十分抱歉。首先这篇文章是参考了@God丶Eye的改写的,地址:https://www.jianshu.com/p/0ad99e598dba,本文稍作修改。
他的demo Github地址:https://github.com/bigeyechou/NetWorkFrame
简单介绍Retrofit、OKHttp和RxJava之间的关系:
各自职责:Retrofit 负责 请求的数据 和 请求的结果,使用 接口的方式 呈现,OkHttp 负责请求的过程,RxJava 负责异步,各种线程之间的切换。
一步一步深入:
1、引入Retrofit的包,在build.gradle文件中添加如下配置:
implementation 'com.google.code.gson:gson:2.6.2'
implementation 'com.alibaba:fastjson:1.2.9'
//导入Gson 库
//导入RxJava 和 RxAndroid
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
implementation 'io.reactivex.rxjava2:rxjava:2.0.5'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
//导入retrofit
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
//转换器,请求结果转换成Model
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
//配合Rxjava 使用
implementation 'com.squareup.okhttp3:logging-interceptor:3.1.2'
//添加HttpLoggingInterceptor进行调试
//butterknife不是必须
implementation 'com.jakewharton:butterknife:7.0.1'
implementation 'com.orhanobut:logger:1.15'
2、创建OkHttpClient.Builder 实例,并且完成相关的配置(包含cache、header、timeout....):
//手动创建一个OkHttpClient并设置超时时间
okHttpBuilder = new OkHttpClient.Builder();
/**
* 设置缓存
*/
File cacheFile = new File(BigEyeApplication.appContext.getExternalCacheDir(), CACHE_NAME);
Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
Interceptor cacheInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!NetUtil.isNetworkConnected()) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response response = chain.proceed(request);
if (!NetUtil.isNetworkConnected()) {
int maxAge = 0;
// 有网络时 设置缓存超时时间0个小时
response.newBuilder()
.header("Cache-Control", "public, max-age=" + maxAge)
.removeHeader(CACHE_NAME)// 清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效
.build();
} else {
// 无网络时,设置超时为4周
int maxStale = 60 * 60 * 24 * 28;
response.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.removeHeader(CACHE_NAME)
.build();
}
return response;
}
};
okHttpBuilder.cache(cache).addInterceptor(cacheInterceptor);
/**
* 设置头信息
*/
Interceptor headerInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
Request.Builder requestBuilder = originalRequest.newBuilder()
.addHeader("Accept-Encoding", "gzip")
.addHeader("Accept", "application/json")
.addHeader("Content-Type", "application/json; charset=utf-8")
.method(originalRequest.method(), originalRequest.body());
requestBuilder.addHeader("Authorization", "Bearer " + BaseConstant.TOKEN);//添加请求头信息,服务器进行token有效性验证
Request request = requestBuilder.build();
return chain.proceed(request);
}
};
okHttpBuilder.addInterceptor(headerInterceptor);
// if (BuildConfig.DEBUG) {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
Logger.d(message);
}
});
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
//设置 Debug Log 模式
okHttpBuilder.addInterceptor(loggingInterceptor);
// }
/**
* 设置超时和重新连接
*/
okHttpBuilder.connectTimeout(DEFAULT_CONNECT_TIMEOUT, TimeUnit.SECONDS);
okHttpBuilder.readTimeout(DEFAULT_WRITE_TIMEOUT, TimeUnit.SECONDS);
okHttpBuilder.writeTimeout(DEFAULT_READ_TIMEOUT, TimeUnit.SECONDS);
//错误重连
okHttpBuilder.retryOnConnectionFailure(true);
3、创建一个Retrofit 实例,并且完成相关的配置:
配置了接口的 BASE_URL 和一个 converter , GsonConverterFactory 是默认提供的 Gson转换器。
retrofit = new Retrofit.Builder()
.client(okHttpBuilder.build())
.addConverterFactory(GsonConverterFactory.create())//json转换成JavaBean
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(BASE_URL)
.build();
4、创建接口,当然这些接口可以全部封装在一个类里面:
httpApi = retrofit.create(HttpApi.class);
HttpApi类为接口封装类,配合RxJava 使用,更改定义的接口,返回值不再是一个 Call ,而是返回的一个 Observble:
//请填写自己的接口名
@GET("api/XXX/GetDoubanMovieBean")
Observable getDataForMap(@QueryMap Map map);
/**
* 通过地址下载一个文件
*/
@GET()
@Streaming
Call downloadFile(@Url String fileUrl);
5、加入RxJava的好处:
RxJava 很强大,能帮我处理很多复杂的场景,如果熟练使用的话,那么能提升我们的开发效率。
6、自定义一个DisposableObserver与Activity 或者 Fragment 建立订阅关系:
public class OnSuccessAndFaultSub extends DisposableObserver
implements ProgressCancelListener {
/**
* 是否需要显示默认Loading
*/
private boolean showProgress = true;
private OnSuccessAndFaultListener mOnSuccessAndFaultListener;
private Context context;
private ProgressDialog progressDialog;
private Class> mClass;
/**
* @param mOnSuccessAndFaultListener 成功回调监听
*/
public OnSuccessAndFaultSub(OnSuccessAndFaultListener mOnSuccessAndFaultListener, Class> tClass) {
this.mOnSuccessAndFaultListener = mOnSuccessAndFaultListener;
this.mClass = tClass;
}
/**
* @param mOnSuccessAndFaultListener 成功回调监听
* @param context 上下文
*/
public OnSuccessAndFaultSub(OnSuccessAndFaultListener mOnSuccessAndFaultListener, Context context, Class> tClass) {
this.mOnSuccessAndFaultListener = mOnSuccessAndFaultListener;
this.context = context;
progressDialog = new ProgressDialog(context);
this.mClass = tClass;
}
/**
* @param mOnSuccessAndFaultListener 成功回调监听
* @param context 上下文
* @param showProgress 是否需要显示默认Loading
*/
public OnSuccessAndFaultSub(OnSuccessAndFaultListener mOnSuccessAndFaultListener, Context context, boolean showProgress) {
this.mOnSuccessAndFaultListener = mOnSuccessAndFaultListener;
this.context = context;
progressDialog = new ProgressDialog(context);
this.showProgress = showProgress;
}
private void showProgressDialog() {
if (showProgress && null != progressDialog) {
progressDialog.show();
}
}
private void dismissProgressDialog() {
if (showProgress && null != progressDialog) {
progressDialog.dismiss();
}
}
/**
* 订阅开始时调用
* 显示ProgressDialog
*/
@Override
public void onStart() {
showProgressDialog();
}
/**
* 完成,隐藏ProgressDialog
*/
@Override
public void onComplete() {
dismissProgressDialog();
progressDialog = null;
}
/**
* 对错误进行统一处理
* 隐藏ProgressDialog
*/
@Override
public void onError(Throwable e) {
try {
if (e instanceof SocketTimeoutException) {//请求超时
} else if (e instanceof ConnectException) {//网络连接超时
// ToastManager.showShortToast("网络连接超时");
mOnSuccessAndFaultListener.onFault("网络连接超时");
} else if (e instanceof SSLHandshakeException) {//安全证书异常
// ToastManager.showShortToast("安全证书异常");
mOnSuccessAndFaultListener.onFault("安全证书异常");
} else if (e instanceof HttpException) {//请求的地址不存在
int code = ((HttpException) e).code();
if (code == 504) {
// ToastManager.showShortToast("网络异常,请检查您的网络状态");
mOnSuccessAndFaultListener.onFault("网络异常,请检查您的网络状态");
} else if (code == 404) {
// ToastManager.showShortToast("请求的地址不存在");
mOnSuccessAndFaultListener.onFault("请求的地址不存在");
} else {
// ToastManager.showShortToast("请求失败");
mOnSuccessAndFaultListener.onFault("请求失败");
}
} else if (e instanceof UnknownHostException) {//域名解析失败
// ToastManager.showShortToast("域名解析失败");
mOnSuccessAndFaultListener.onFault("域名解析失败");
} else {
// ToastManager.showShortToast("error:" + e.getMessage());
mOnSuccessAndFaultListener.onFault("error:" + e.getMessage());
}
} catch (Exception e2) {
e2.printStackTrace();
} finally {
Log.e("OnSuccessAndFaultSub", "error:" + e.getMessage());
// mOnSuccessAndFaultListener.onFault("error:" + e.getMessage());
dismissProgressDialog();
progressDialog = null;
}
}
/**
* 当result等于1回调给调用者,否则自动显示错误信息,若错误信息为401跳转登录页面。
* ResponseBody body = response.body();//获取响应体
* InputStream inputStream = body.byteStream();//获取输入流
* byte[] bytes = body.bytes();//获取字节数组
* String str = body.string();//获取字符串数据
*/
@Override
public void onNext(ResponseBody body) {
try {
final String result = CompressUtils.decompress(body.byteStream());
Log.e("body", result);
JSONObject jsonObject = new JSONObject(result);
int resultCode = jsonObject.getInt("ErrorCode");
if (resultCode == 1) {//成功
if (mClass == null) {
mOnSuccessAndFaultListener.onSuccess(result);
} else {
mOnSuccessAndFaultListener.onSuccess(JSON.parseObject(result, mClass));
}
} else {
String errorMsg = jsonObject.getString("ErrorMessage");
mOnSuccessAndFaultListener.onFault(errorMsg);
Log.e("OnSuccessAndFaultSub", "errorMsg: " + errorMsg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 取消ProgressDialog的时候,取消对observable的订阅,同时也取消了http请求
*/
@Override
public void onCancelProgress() {
if (!this.isDisposed()) {
this.dispose();
}
}
}
7、再看看接口实现出调用:
/**
* 获取数据
*/
public static void getData(int pageNumber, int userId, DisposableObserver subscriber) {
Map map = new HashMap<>();
map.put("start", pageNumber);
map.put("count", userId);
Observable observable = HttpMethods.getInstance().getHttpApi().getDataForMap(map);
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
8、在Activity与Fragment中使用:
MovieSubscribe.getData(pageNumber, userId, new OnSuccessAndFaultSub(new OnSuccessAndFaultListener() {
@Override
public void onSuccess(Object result) {
//成功
Toast.makeText(MainActivity.this, "请求成功:", Toast.LENGTH_SHORT).show();
DoubanMovieBean doubanMovieBean = (DoubanMovieBean) result;
}
@Override
public void onFault(String errorMsg) {
//失败
Toast.makeText(MainActivity.this, "请求失败:" + errorMsg, Toast.LENGTH_SHORT).show();
}
}, DoubanMovieBean.class));
我将返回数据封装为一个Class>实体,当然返回后直接可以赋值给请求之前传入的实体类:DoubanMovieBean。
代码需要的可以联系我,也可以参考@God丶Eye的源码哈!
也可以下载我修改过后的,地址:https://download.csdn.net/download/jocerly/10816728