Demo地址:https://github.com/LJYcoder/DevRing
学习/参考地址:
Retrofit:
整体教程 http://blog.youkuaiyun.com/jdsjlzx/article/details/52015347
文件上传 http://blog.youkuaiyun.com/jdsjlzx/article/details/52246114
文件下载 http://www.jianshu.com/p/060d55fc1c82
Https请求 http://blog.youkuaiyun.com/dd864140130/article/details/52625666
异常处理 http://blog.youkuaiyun.com/mq2553299/article/details/70244529
失败重试 http://blog.youkuaiyun.com/johnny901114/article/details/51539708
生命周期 http://android.jobbole.com/83847 | http://mp.weixin.qq.com/s/eedFDMIQe30rQmryLeif_Q
RxJava:
整体教程(RxJava1) https://gank.io/post/560e15be2dca930e00da1083
整体教程(RxJava2) https://mp.weixin.qq.com/s/UAEgdC2EtqSpEqvog0aoZQ
操作符 https://zhuanlan.zhihu.com/p/21926591
使用场景 http://blog.youkuaiyun.com/theone10211024/article/details/50435325
1.x与2.x区别 http://blog.youkuaiyun.com/qq_35064774/article/details/53045298
前言
Retrofit是目前主流的网络请求框架,功能强大,操作便捷。
RxJava是实现异步操作的库。可在线程间快速切换,同时提供许多操作符,使一些复杂的操作代码变得清晰有条理。
两者结合使用后,使得网络请求更加简洁,尤其在嵌套请求等特殊场景大有作为。
本文侧重于介绍Retrofit网络请求,以及它是如何结合RxJava使用的。还没了解过RxJava的建议先到上面贴出的参考地址学习,以便更好明白两者结合的过程。
文章篇幅较长,因为希望尽可能涵盖常用、实用的模块。
demo以及文章中的RxJava部分,已从1.x更新到2.x。
介绍
下面通过配置,请求,异常处理,生命周期管理,失败重试,封装,混淆这几个部分来介绍。
1. 配置
1.1 添加依赖
//Rxjava
compile 'io.reactivex.rxjava2:rxjava:2.1.6'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
//Retrofit
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.8.0'
1.2 开启LOG日志
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
//启用Log日志
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
okHttpClientBuilder.addInterceptor(loggingInterceptor);
开启后,则可以在Log日志中看到网络请求相关的信息了,如请求地址,请求状态码,返回的结果等。
1.3 开启GSON转换
Retrofit.Builder retrofitBuilder = new Retrofit.Builder();
//配置转化库,采用Gson
retrofitBuilder.addConverterFactory(GsonConverterFactory.create());
开启后,会自动把请求返回的结果(json字符串)自动转化成与其结构相符的实体。
1.4 采用RXJAVA
Retrofit.Builder retrofitBuilder = new Retrofit.Builder();
//配置回调库,采用RxJava
retrofitBuilder.addCallAdapterFactory(RxJava2CallAdapterFactory.create());
1.5 设置基础请求路径BASEURL
Retrofit.Builder retrofitBuilder = new Retrofit.Builder();
//服务器地址,基础请求路径,最好以"/"结尾
retrofitBuilder.baseUrl("https://api.douban.com/");
1.6 设置请求超时
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
//设置请求超时时长为15秒
okHttpClientBuilder.connectTimeout(15, TimeUnit.SECONDS);
1.7 设置缓存
Interceptor cacheIntercepter=new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
//对request的设置用来指定有网/无网下所走的方式
//对response的设置用来指定有网/无网下的缓存时长
Request request = chain.request();
if (!NetworkUtil.isNetWorkAvailable(mContext)) {
//无网络下强制使用缓存,无论缓存是否过期,此时该请求实际上不会被发送出去。
//有网络时则根据缓存时长来决定是否发出请求
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE).build();
}
Response response = chain.proceed(request);
if (NetworkUtil.isNetWorkAvailable(mContext)) {
//有网络情况下,超过1分钟,则重新请求,否则直接使用缓存数据
int maxAge = 60; //缓存一分钟
String cacheControl = "public,max-age=" + maxAge;
//当然如果你想在有网络的情况下都直接走网络,那么只需要
//将其超时时间maxAge设为0即可
return response.newBuilder()
.header("Cache-Control",cacheControl)
.removeHeader("Pragma").build();
} else {
//无网络时直接取缓存数据,该缓存数据保存1周
int maxStale = 60 * 60 * 24 * 7 * 1; //1周
return response.newBuilder()
.header("Cache-Control", "public,only-if-cached,max-stale=" + maxStale)
.removeHeader("Pragma").build();
}
}
};
File cacheFile = new File(mContext.getExternalCacheDir(), "HttpCache");//缓存地址
Cache cache = new Cache(cacheFile, 1024 * 1024 * 50); //大小50Mb
//设置缓存方式、时长、地址
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
okHttpClientBuilder.addNetworkInterceptor(cacheIntercepter);
okHttpClientBuilder.addInterceptor(cacheIntercepter);
okHttpClientBuilder.cache(cache);
1.8 设置HEADER
可统一设置
Interceptor headerInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
Request.Builder builder = originalRequest.newBuilder();
//设置具体的header内容
builder.header("timestamp", System.currentTimeMillis() + "");
Request.Builder requestBuilder =
builder.method(originalRequest.method(), originalRequest.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
};
//设置统一的header
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
okHttpClientBuilder.addInterceptor(getHeaderInterceptor());
也可在请求方法中单独设置
@Headers("Cache-Control: max-age=120")
@GET("请求地址")
Observable<HttpResult> getInfo();
或者
@GET("请求地址")
Observable<HttpResult> getInfo(@Header("token") String token);
1.9 设置HTTPS访问
现在不少服务器接口采用了https的形式,所以有时就需要设置https访问。
下面列举“客户端内置证书”时的配置方法,其他方式请参考 “客户端内置证书”时的配置方法
//设置https访问(验证证书,请把服务器给的证书文件放在R.raw文件夹下)
okHttpClientBuilder.sslSocketFactory(getSSLSocketFactory(mContext, new int[]{
R.raw.tomcat}));
okHttpClientBuilder.hostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
getSSLSocketFactory()方法如下:
//设置https证书
protected static SSLSocketFactory getSSLSocketFactory(Context context, int[] certificates) {
if (context == null) {
throw new NullPointerException("context == null");
}
//CertificateFactory用来证书生成
CertificateFactory certificateFactory;
try {
certificateFactory = CertificateFactory.getInstance("X.509");
//Create a KeyStore containing our trusted CAs
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
for (int i = 0; i < certificates.length; i++) {
//读取本地证书
InputStream is = context.getResources().openRawResource(certificates[i]);
keyStore.setCertificateEntry(String.valueOf(i), certificateFactory
.generateCertificate(is));
if (is != null) {
is.close();
}
}
//Create a TrustManager that trusts the CAs in our keyStore
Tr