这玩意平时弄一次就不管了,时间久了就忘了。
收藏几个帖子,忘了拿来看看
https://www.jianshu.com/p/0fda3132cf98
https://www.jianshu.com/p/308f3c54abdd
官方的https://github.com/square/retrofit
文档https://square.github.io/retrofit/
相关库
// Okhttp库,可以省略,retrofit自带了
//implementation 'com.squareup.okhttp3:okhttp:3.10.0'
// implementation 'io.reactivex.rxjava2:rxjava:2.1.12' //省略,已经自带了
// Retrofit库
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation "com.squareup.retrofit2:converter-gson:2.4.0"
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
implementation 'com.google.code.gson:gson:2.8.2'
implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0' //如果需要打印log的话需要这个
一般都用的gson解析,万一用别的看下
数据解析器 Gradle依赖
Gson com.squareup.retrofit2:converter-gson:2.0.2
Jackson com.squareup.retrofit2:converter-jackson:2.0.2
Simple XML com.squareup.retrofit2:converter-simplexml:2.0.2
Protobuf com.squareup.retrofit2:converter-protobuf:2.0.2
Moshi com.squareup.retrofit2:converter-moshi:2.0.2
Wire com.squareup.retrofit2:converter-wire:2.0.2
Scalars com.squareup.retrofit2:converter-scalars:2.0.2
网上找了个缓存的代码,结果加载一次数据以后,我把网断了,再进去测试结果挂了
retrofit cache 504 Unsatisfiable Request (only-if-cached) error
cookie的使用这里写了参考文章,需要的话可以去看
https://www.cnblogs.com/Jason-Jan/p/8010795.html
我下边用的hy的https://github.com/hongyangAndroid/okhttputils 我把里边cookie的类copy到工程里了。
封装的带缓存的代码
import com.charliesong.wanandroid.retrofit.cookie.CookieJarImpl
import com.charliesong.wanandroid.retrofit.cookie.PersistentCookieStore
import okhttp3.*
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import okhttp3.logging.HttpLoggingInterceptor
import java.io.File
import java.util.concurrent.TimeUnit
object MyAPIManager {
private val host = "http://www.wanandroid.com"
private fun getRetrofit(): Retrofit {
//缓存容量
val SIZE_OF_CACHE = (50 * 1024 * 1024).toLong() // 10 MiB
//缓存路径
val cacheFile = "${MyApplication.getApp().getCacheDir()}/http"
val cache = Cache(File(cacheFile), SIZE_OF_CACHE)
// Cookie 持久化
// val cookieJar = PersistentCookieJar(SetCookieCache(), SharedPrefsCookiePersistor(InitApp.AppContext))
//利用okhttp实现缓存
val clientBuilder = OkHttpClient.Builder()
.cookieJar(CookieJarImpl(PersistentCookieStore(MyApplication.getApp())))
// //有网络时的拦截器
.addNetworkInterceptor(rewrite_response_interceptor)
// //没网络时的拦截器
.addInterceptor(rewrite_response_interceptor_offline)
.cache(cache)
// .connectTimeout(10, TimeUnit.SECONDS)
// .readTimeout(15, TimeUnit.SECONDS)
// .writeTimeout(15, TimeUnit.SECONDS)
// .retryOnConnectionFailure(true)
if (BuildConfig.DEBUG) {
val interceptor = HttpLoggingInterceptor()
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
clientBuilder.addInterceptor(interceptor)
}
return Retrofit.Builder().baseUrl(host)
.client(clientBuilder.build())
.addConverterFactory(GsonConverterFactory.create()) //结果解析为gson对象用这个
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //如果要用rx接口返回Observable加上这个
.build()
}
private var myAPI: MyAPI? = null
fun getAPI(): MyAPI {
return myAPI ?: getRetrofit().create(MyAPI::class.java)
}
private val rewrite_response_interceptor = Interceptor { chain ->
val originalResponse = chain.proceed(chain.request())
//如果接口里写了@Headers("Cache-Control: max-age=60")缓存时间,那么可以用下边的代码把接口的缓存时间添加到相应的结果里。
// var requestCacheControl = chain.request().header("Cache-Control")
// var haveSetCacheTime = requestCacheControl != null && (requestCacheControl.contains("max-age"))
// if (haveSetCacheTime) {
// return@Interceptor originalResponse.newBuilder()
// .addHeader("Cache-Control",requestCacheControl)
// .removeHeader("Pragma").build()
// }
val cacheControl = originalResponse.header("Cache-Control")
//这里判断的都是服务器返回的缓存条件
if (cacheControl == null || cacheControl.contains("no-store") || cacheControl.contains("no-cache") ||
cacheControl.contains("must-revalidate") || cacheControl.contains("max-age=0")) {
var build = originalResponse.newBuilder()
.removeHeader("Pragma")// 清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效
.removeHeader("Cache-Control")
.header("Cache-Control", "public, max-age=" + 5)//单位是秒,就是5秒内不请求服务器
build.build()
} else {
originalResponse
}
}
private val rewrite_response_interceptor_offline = Interceptor { chain ->
var request = chain.request()
if (!NormalUtil.isNetworkConnected(MyApplication.getApp())) {
request = request.newBuilder()
// .header("Cache-Control", "public, only-if-cached")//这个不靠谱,没网络的时候不加载缓存
.cacheControl(CacheControl.FORCE_CACHE)
.build()
}
var originalResponse = chain.proceed(request)
if (NormalUtil.isNetworkConnected(MyApplication.getApp())) {
// val cacheControl = request.cacheControl().toString()
// originalResponse.newBuilder()
// .header("Cache-Control", "public, max-age=" + 0)//单位是秒
// .removeHeader("Pragma")
// .build()
originalResponse
} else {
val maxTime = 4 * 24 * 60 * 60
originalResponse.newBuilder()
//这里的设置的是我们的没有网络的缓存时间,想设置多少就是多少。
.header("Cache-Control", "public, only-if-cached, max-stale=$maxTime")
.removeHeader("Pragma")
.build()
}
}
}
简单说明下
如果我在代码里添加了缓存的header如下
@Headers("Cache-Control: max-age=60")
@GET("/article/list/{page}/json")
那么如何生效?
可以在addNetworkInterceptor这个interceptor里处理
var requestCacheControl=chain.request().header("Cache-Control")
就可以获取到header了,完事我们可以判断里边有没有设置max-age,如果设置了,那下边就用这个值,可以参考上边代码里注释的部分
比如说每日推荐的接口,每天我们可能就推荐一篇文章,那么这个缓存时间可以设置大点。
2个拦截器的说明
addNetworkInterceptor添加的是网络拦截器,他会在在request和resposne是分别被调用一次,addinterceptor添加的是aplication拦截器,他只会在response被调用一次
看这里https://blog.csdn.net/u010286855/article/details/52608485
常用的api写法
下边有path占位用,还有query和querymap,用来拼接问号后的参数
@GET("/article/list/{page}/json")
fun getTreeArticle(@Path("page") page: Int, @Query("cid") cid: Int):Call<BaseListData<ArticleBean>>
/**如果问号后有多个参数,可以使用map,省事*/
@GET("/article/list/{page}/json")
fun getTreeArticle2(@Path("page") page: Int, @QueryMap map:HashMap<String,Int>):Call<BaseListData<ArticleBean>>
登陆返回的信息cookie
wanandroid D/OkHttp: Server: Apache-Coyote/1.1
wanandroid D/OkHttp: Set-Cookie: JSESSIONID=5FB89C5317F08DED80500938CD01AEA1; Path=/; HttpOnly
wanandroid D/OkHttp: Set-Cookie: loginUserName=12345678912; Expires=Sat, 04-Aug-2018 09:29:37 GMT; Path=/
wanandroid D/OkHttp: Set-Cookie: loginUserPassword=aaaaaa; Expires=Sat, 04-Aug-2018 09:29:37 GMT; Path=/
wanandroid D/OkHttp: Content-Type: application/json;charset=UTF-8
wanandroid D/OkHttp: Transfer-Encoding: chunked
wanandroid D/OkHttp: Date: Thu, 05 Jul 2018 09:29:37 GMT
wanandroid D/OkHttp: Cache-Control: public, max-age=5000
wanandroid D/OkHttp: {"data":{"collectIds":[],"email":"","icon":"","id":7280,"password":"aaaaaa","type":0,"username":"12345678912"},"errorCode":0,"errorMsg":""}