retrofit使用

这玩意平时弄一次就不管了,时间久了就忘了。
收藏几个帖子,忘了拿来看看
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":""}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容