美文网首页
retrofit使用

retrofit使用

作者: 有点健忘 | 来源:发表于2018-07-06 15:12 被阅读20次

这玩意平时弄一次就不管了,时间久了就忘了。
收藏几个帖子,忘了拿来看看
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":""}

相关文章

网友评论

      本文标题:retrofit使用

      本文链接:https://www.haomeiwen.com/subject/eoubyftx.html