Android Retrofit 给你的接口加上缓存

news/2024/12/28 1:49:44/

转载请注明出处:https://blog.csdn.net/kong_gu_you_lan/article/details/131200501?spm=1001.2014.3001.5501

本文出自 容华谢后的博客

往期回顾:

Android Retrofit + RxJava使用详解

Android 探讨一下Retrofit封装的最佳姿势

Android 谈谈我所理解的MVP

0.写在前面

最近要对接口做一些优化,于是就想着给一些频繁获取数据的接口加上缓存功能,网上搜上一搜,一般都只支持GET请求,但是因为服务器那边接口比较特殊,参数较多的获取数据接口都是用的POST,用原生的缓存方式还不行。

那只能自己实现一个,支持GET、POST请求方式,为了安全还要支持缓存数据加密,放到项目里试了试,还算比较稳定,于是便有了此篇文章。

1.流程

先看下整体的流程,还是通过OkHttp的拦截器实现的,拦截到客户端的请求,如果没有缓存,就去服务器请求数据,然后缓存到本地,然后加密。

如果有缓存,就判断下缓存的时间,没过期就返回给客户端缓存数据,过期了就再去服务器取一份,重复上面的步骤。

缓存流程

2.实现

实现一个简单的接口请求,访问百度页面,然后测试下缓存的效果:

val retrofit = Retrofit.Builder().baseUrl("https://api.github.com/").client(getOkHttpClient()).build()binding.btnRequest.setOnClickListener {val service = retrofit.create(RetrofitService::class.java)val call = service.request("https://www.baidu.com")call.enqueue(object : Callback<ResponseBody> {override fun onResponse(call: Call<ResponseBody>,response: Response<ResponseBody>) {val result = response.body()?.string() ?: ""binding.tvResult.text = resultLog.i("http返回:", result)}override fun onFailure(call: Call<ResponseBody>, t: Throwable) {}})
}

主要看下getOkHttpClient()方法:

/*** 获取OkHttpClient** @return OkHttpClient*/
private fun getOkHttpClient(): OkHttpClient {// 定制OkHttpval httpClientBuilder = OkHttpClient.Builder()// 添加响应数据缓存拦截器httpClientBuilder.addInterceptor(CacheInterceptor(this, "key"))return httpClientBuilder.build()
}/*** 缓存数据拦截器** @param mContext Context* @param key      秘钥*/
private class CacheInterceptor(private val mContext: Context,private val key: String
) : Interceptor {override fun intercept(chain: Interceptor.Chain): okhttp3.Response {val request = chain.request()val cacheKey = HttpUtils.getCacheKey(request)val cacheFile = File(HttpUtils.getCacheFile(mContext), cacheKey)// 缓存时间1小时val cacheTime = 3600000Lval cacheEnable = (System.currentTimeMillis() - cacheFile.lastModified()) < cacheTimeif (cacheEnable && cacheFile.exists() && cacheFile.length() > 0) {Log.i("CacheInterceptor","[intercept] 缓存模式 url:${HttpUtils.getRequestUrl(request)} " +"过期时间:${HttpUtils.dateTimeToString(cacheFile.lastModified() + cacheTime)}")val cache = SecurityUtils.decryptContent(cacheFile.readText(), key)if (cache.isNotEmpty() && cache.startsWith("{") && cache.endsWith("}")) {return okhttp3.Response.Builder().code(200).body(cache.toResponseBody()).request(request).message("from disk cache").protocol(Protocol.HTTP_2).build()}}val response = chain.proceed(request)val responseBody = response.body ?: return responseval data = responseBody.bytes()val dataString = String(data)// 写入缓存if (response.code == 200) {// Json数据写入缓存cacheFile.writeText(SecurityUtils.encryptContent(dataString, key))} else {cacheFile.writeText("")}return response.newBuilder().body(data.toResponseBody(responseBody.contentType())).build()}
}

代码不是很多,加密的逻辑放在SecurityUtils工具类中了,文章末尾下载源码就可以。

加密后的文件是这样的,文件里存储的内容是十六进制字符串:

文件目录

3.注意

这个key是秘钥,可以自己自定义,获取这个秘钥的方法,可以写在so里,也可以写成字符数组的方式,通过某种组合获取到,不要固定一个字符串就行,这样比较安全:

// 添加响应数据缓存拦截器
httpClientBuilder.addInterceptor(CacheInterceptor(this, "key"))

在写入缓存这里,判断了code是200就写入缓存,实际业务中,可能有自己的定义方式,code返回200只能证明接口通了,服务器的逻辑有自己的规则,比如在返回数据中也有一个code标记,可以在if判断里再加一个业务的判断,只有业务返回了成功,再写入缓存。

// 写入缓存
if (response.code == 200) {// Json数据写入缓存cacheFile.writeText(SecurityUtils.encryptContent(dataString, key))
} else {cacheFile.writeText("")
}

4.原生GET请求缓存

有的同学只想用原生的方法去缓存GET请求,在此附上代码:

override fun intercept(chain: Interceptor.Chain): Response {var request = chain.request()// GET请求if ("GET" == request.method) {return if (checkNetwork(mContext)) {request = request.newBuilder().cacheControl(CacheControl.FORCE_NETWORK).build()val response = chain.proceed(request)response.newBuilder().header("Cache-Control", "public, max-age=0").removeHeader("Pragma").build()} else {request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build()val response = chain.proceed(request)return response.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=604800").removeHeader("Pragma").build()}}// POST请求return chain.proceed(request)
}

5.写在最后

GitHub地址:https://github.com/alidili/Demos/tree/master/RetrofitCacheDemo

到这里,Retrofit的缓存功能就介绍完了,如有问题可以给我留言评论或者在GitHub中提交Issues,谢谢!


http://www.ppmy.cn/news/380264.html

相关文章

互联网JAVA工程师必背面试题和项目面试通关要点(带答案)

前言 大家好&#xff0c;前几天我将各个大厂的高频考点以及 Java 岗需掌握的核心知识整理出的 Java 核心知识大全分享给了大家&#xff0c;今天为了能让看过这份资料的小伙伴更加好地去理解和灵活运用。小编今天将把前段时间和那份资料一块儿收集的 1100 道 Java 岗大厂面试真…

如何保证缓存数据的一致性?

缓存查询 先查询缓存若失败&#xff0c;则查询数据库重建缓存 缓存更新 缓存更新可以沿着 先更新数据库&#xff0c;再更新缓存先更新缓存&#xff0c;再更新数据库 在常规场景下&#xff0c;两者均可以&#xff0c;不会出现不一致问题。 不过如果后更新的失败了&#xf…

2023年计算机专业不好找工作的原因是什么?

计算机专业是一个就业前景较好的领域&#xff0c;但仍然存在一些因素可能导致计算机专业毕业生找工作相对困难。以下是一些可能的原因&#xff1a; **市场竞争激烈&#xff1a;**计算机专业吸引了大量的学生&#xff0c;导致市场上存在大量的竞争。大学生毕业人数增加&#xf…

计算机存储系统的优势是什么意思,电脑的存储空间大了有什么好处吗?

当电脑开机后&#xff0c;你每打开一个软件&#xff0c;电脑的内存都会记录这个软件的信息&#xff0c;过程就是&#xff0c;开机后第一次打开软件时&#xff0c;电脑的处理器会从电脑内存中调取软件的信息&#xff0c;当然这时候在内存中是找不到的&#xff0c;因为你刚开机&a…

计算机的处理器意义,处理器对电脑的作用

大家好&#xff0c;我是时间财富网智能客服时间君&#xff0c;上述问题将由我为大家进行解答。 处理器对电脑的系统的运行速度有影响&#xff0c;它的性能指标直接决定了微机系统的性能指标&#xff1b;它的功能主要是解释计算机指令以及处理计算机软件中的数据。 中央处理器(C…

PCB封装设计实践和文件模板

在之前的文章 详解AD(Altium Designer 23)中的机械层 - 1、详解AD(Altium Designer 23)中的机械层 - 2 中&#xff0c;我们详细介绍了AD中机械层的相关设置&#xff0c;今天结合PCB封装的设计&#xff0c;给出一些实践建议&#xff0c;并分享一个文件模板。 PCB封装设计 PCB&…

计算机两个硬盘的作用,电脑装2个硬盘有什么好处与坏处

总体来说1个2tb的硬盘好&#xff01; 从功耗来说&#xff1a; 1个2tb的硬盘比2个1tb的硬盘功耗要低得多&#xff0c;假如一个1tb硬盘的功耗是50w&#xff0c;两个就是100w&#xff0c;那么如若1个2tb的硬盘是80w的话&#xff0c;1个2tb的硬盘占优势。 从储存速度来说&#xff1…

计算机系统分盘作用,电脑为什么要分区,分区的好处

您可能感兴趣的话题&#xff1a; 分区 核心提示&#xff1a;今天小编为大家介绍一下电脑为什么需要分区&#xff0c;分区有什么好处。 今天小编为大家介绍一下电脑为什么需要分区&#xff0c;分区有什么好处。 一般笔记本买回来时都只有一个C盘。 1、当系统需要还原时&#xff…