你不知道的Retrofit缓存库RxCache

Android-基于RxJava2Retrofit2RxCache的网络请求框架 基于RxJava2 Retrofit2 RxCache的网络请求框架 立即下载
推荐:看到如此多的MVP+Dagger2+Retrofit+Rxjava项目,轻松拿star,心动了吗?MVPArms是一个 MVP+Dagger2+Retrofit+Rxjava快速集成框架(目前Dagger应用最复杂的框架),自带上万字文档以及自动生成MVP和Dagger2文件等功能,你只用专注于逻辑,其他都交给MVPArms,快来构建自己的MVP+Dagger2+Retrofit+Rxjava项目吧!

原文地址: http://www.jianshu.com/p/b58ef6b0624b

前言

Retrofit无疑是当下最火的网络请求库,与同门师兄Okhttp配合使用,简直是每个项目的标配,因为Okhttp自带缓存,所以很多人并不关心其他缓存库,但是使用过Okhttp缓存的小伙伴,肯定知道Okhttp的缓存必须配合Header使用,比较麻烦,也不够灵活,所以现在为大家推荐一款专门为Retrifit打造的缓存库RxCache

项目地址: RxCache Demo地址: RxCacheSample

简介

RxCache使用注解来为Retrofit配置缓存信息,内部使用动态代理和Dagger来实现,这个库的资料相对较少,官方的Demo又全是英文的,这无疑给开发者增加了使用难度,其实我英文也不好,但是源码是通用的啊,所以我为大家从源码的角度来讲解此库,此库源码的难点其实都在Dagger注入上,我先为大家讲解用法,后面会再写篇文章讲解源码,在学习Dagger的朋友除了建议看看我的MVPArms外,还可以看看这个RxCache的源码,能学到很多东西,先给张RxCache的架构图,让大家尝尝鲜,请期待我后面的源码分析

使用

1.定义接口,和Retrofit类似,接口中每个方法和Retrofit接口中的方法一一对应,每个方法的参数中必须传入对应Retrofit接口方法的返回值(返回值必须为Observable,否则报错),另外几个参数DynamicKey,DynamicKeyGroup和EvictProvider不是必须的,但是如果要传入,每个都只能传入一个对象,否则报错,这几个参数的意义是初学者最困惑的,后面会分析

/**
 * 此为RxCache官方Demo
 */
public interface CacheProviders {

    @LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES)
    Observable<Reply<List<Repo>>> getRepos(Observable<List<Repo>> oRepos, DynamicKey userName, EvictDynamicKey evictDynamicKey);

    @LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES)
    Observable<Reply<List<User>>> getUsers(Observable<List<User>> oUsers, DynamicKey idLastUserQueried, EvictProvider evictProvider);

    Observable<Reply<User>> getCurrentUser(Observable<User> oUser, EvictProvider evictProvider);
}

2.将接口实例化,和Retrofit构建方式类似,将接口通过using方法传入,返回一个接口的动态代理对象,调用此对象的方法传入对应参数就可以实现缓存了,通过注解和传入不同的参数可以实现一些自定义的配置, so easy~

CacheProviders cacheProviders = new RxCache.Builder()
                .persistence(cacheDir, new GsonSpeaker())
                .using(CacheProviders.class);

详解

其实RxCache的使用比较简单,上面的两步就可以轻松的实现缓存,此库的的特色主要集中在对缓存的自定义配置,所以我来主要讲讲那些参数和注解是怎么回事?

参数

Observable

此Observable的意义为需要将你想缓存的Retrofit接口作为参数传入(返回值必须为Observable),RxCache会在没有缓存,或者缓存已经过期,或者EvictProvider为true时,通过这个Retrofit接口重新请求最新的数据,并且将服务器返回的结果包装成Reply返回,返回之前会向内存缓存和磁盘缓存中各保存一份

值得一提的是,如果需要知道返回的结果是来自哪里(本地,内存还是网络),是否加密,则可以使用Observable<Reply<List<Repo>>>作为方法的返回值,这样RxCache则会使用Reply包装结果,如果没这个需求则直接在范型中声明结果的数据类型Observable<List<Repo>>

例外

如果构建RxCache的时候将useExpiredDataIfLoaderNotAvailable设置成true,会在数据为空或者发生错误时,忽视EvictProvider为true或者缓存过期的情况,继续使用缓存(前提是之前请求过有缓存)

DynamicKey & DynamicKeyGroup

有很多开发者最困惑的就是这两个参数的意义,两个一起传以及不传会有影响吗?说到这里就要提下,RxCache是怎么存储缓存的,RxCache并不是通过使用URL充当标识符来储存和获取缓存的

那是什么呢?

没错RxCache就是通过这两个对象加上上面CacheProviders接口中声明的方法名,组合起来一个标识符,通过这个标识符来存储和获取缓存

标识符规则为:

方法名 + $d$d$d$" + dynamicKey.dynamicKey + "$g$g$g$" + DynamicKeyGroup.group

dynamicKey或DynamicKeyGroup为空时则返回空字符串,即什么都不传的标识符为:

"方法名$d$d$d$$g$g$g$"

什么意思呢?

比如RxCache,的内存缓存使用的是Map,它就用这个标识符作为Key,put和get数据(本地缓存则是将这个标识符作为文件名,使用流写入或读取这个文件,来储存或获取缓存),如果储存和获取的标识符不一致那就取不到想取的缓存

和我们有什么关系呢?

举个例子,我们一个接口具有分页功能,我们使用RxCache给他设置了3分钟的缓存,如果这两个对象都不传入参数中,它会默认使用这个接口的方法名去存储和获取缓存,意思是我们之前使用这个接口获取到了第一页的数据,三分钟以内多次调用这个接口,请求其他分页的数据,它返回的缓存还是第一页的数据,直到缓存过期,所以我们现在想具备分页功能,必须传入DynamicKey,DynamicKey内部存储有一个key,我们在构建的时候传入页数,RxCache将会根据不同的页数分别保存一份缓存,它内部做的事就是将方法名+DynamicKey变成一个String类型的标识符去获取和存储缓存

DynamicKey和DynamicKeyGroup有什么关系呢

DynamicKey存储有一个Key,DynamicKey的应用场景: 请求同一个接口,需要参照一个变量的不同返回不同的数据,比如分页,构造时传入页数就可以了

DynamicKeyGroup存储有两个key,DynamicKeyGroup是在DynamicKey基础上的加强版,应用场景:请求同一个接口不仅需要分页,每页又需要根据不同的登录人返回不同的数据,这时候构造DynamicKeyGroup时,在构造函数中第一个参数传页数,第二个参数传用户标识符就可以了

理论上DynamicKey和DynamicKeyGroup根据不同的需求只用传入其中一个即可,但是也可以两个参数都传,以上面的需求为例,两个参数都传的话,它会先取DynamicKey的Key(页数)然后再取DynamicKeyGroup的第二个Key(用户标识符),加上接口名组成标识符,来获取和存储数据,这样就会忽略DynamicKeyGroup的第一个Key(页数)

EvictProvider & EvictDynamicKey & EvictDynamicKeyGroup

这三个对象内部都保存有一个boolean类型的字段,其意思为是否驱逐(使用或删除)缓存,RxCache在取到未过期的缓存时,会根据这个boolean字段,考虑是否使用这个缓存,如果为true,就会重新通过Retrofit获取新的数据,如果为false就会使用这个缓存

这三个对象有什么关系呢?

这三个对象是相互继承关系,继承关系为EvictProvider < EvictDynamicKey < EvictDynamicKeyGroup,这三个对象你只能传其中的一个,多传一个都会报错,按理说你不管传那个对象都一样,因为里面都保存有一个boolean字段,根据这个字段判断是否使用缓存

不同在哪呢?

如果有未过期的缓存,并且里面的boolean为false时,你传这三个中的哪一个都是一样的,但是在boolean为true时,这时就有区别了,RxCache会在Retrofit请求到新数据后,在boolean为true时删除对应的缓存

删除规则是什么呢?

还是以请求一个接口,该接口的数据会根据不同的分页返回不同的数据,并且同一个分页还要根据不同用户显示不同的数据为例

三个都不传,RxCache会自己new EvictProvider(false);,这样默认为false就不会删除任何缓存

EvictDynamicKeyGroup 只会删除对应分页下,对应用户的缓存

EvictDynamicKey 会删除那个分页下的所有缓存,比如你请求的是第一页下user1的数据,它不仅会删除user1的数据还会删除当前分页下其他user2,user3…的数据

EvictProvider 会删除当前接口下的所有缓存,比如你请求的是第一页的数据,它不仅会删除第一页的数据,还会把这个接口下其他分页的数据全删除

所以你可以根据自己的逻辑选择传那个对象,如果请求的这个接口没有分页功能,这时你不想使用缓存,按理说你应该传EvictProvider,并且在构造时传入true,但是你如果传EvictDynamicKey和EvictDynamicKeyGroup达到的效果也是一样

注解

@LifeCache

@LifeCache顾名思义,则是用来定义缓存的生命周期,当Retrofit获取到最新的数据时,会将数据及数据的配置信息封装成Record,在本地和内存中各保存一份,Record中则保存了@LifeCache的值(毫秒)和当前数据请求成功的时间(毫秒)timeAtWhichWasPersisted

以后每次取缓存时,都会判断timeAtWhichWasPersisted+@LifeCache的值是否小于当前时间(毫秒),小于则过期,则会立即清理当前缓存,并使用Retrofit重新请求最新的数据,如果EvictProvider为true不管缓存是否过期都不会使用缓存

@EncryptKey & @Encrypt

这两个注解的作用都是用来给缓存加密,区别在于作用域不一样

@EncryptKey是作用在接口上

@EncryptKey("123")
public interface CacheProviders {

}

而@Encrypt是作用在方法上

@EncryptKey("123")
public interface CacheProviders {

    @Encrypt
    Observable<Reply<User>> getCurrentUser(Observable<User> oUser, EvictProvider evictProvider);
}

}

如果需要给某个接口的缓存做加密的操作,则在对应的方法上加上@Encrypt,在存储和获取缓存时,RxCache就会使用@EncryptKey的值作为Key给缓存数据进行加解密,因此每个Interface中的所有的方法都只能使用相同的Key

值得注意的时,RxCache只会给本地缓存进行加密操作,并不会给内存缓存进行加密,给本地数据加密使用的是Java自带的CipherInputStream,解密使用的是CipherOutputStream

@Expirable

还记得我们在构建RxCache时,有一个setMaxMBPersistenceCache方法,这个可以设置,本地缓存的最大容量,单位为MB,如果没设置则默认为100MB

这个最大容量和@Expirable又有什么关系呢?

当然有!还记得我之前说过在每次Retrofit重新获取最新数据时,返回数据前会将最新数据在内存缓存和本地缓存中各存一份

存储完毕后,会检查现在的本地缓存大小,如果现在本地缓存中存储的所有缓存大小加起来大于或者等于setMaxMBPersistenceCache中设置的大小(默认为100MB)的百分之95,RxCache就会做一些操作,将总的缓存大小控制在百分之70以下

做的什么操作?

很简单,RxCache会遍历,构建RxCache时传入的cacheDirectory中的所有缓存数据,一个个删除直到总大小小于百分70,遍历的顺序不能保证,所以搞不好对你特别重要的缓存就被删除了,这时@Expirable就派上用场了,在方法上使用它并且给它设置为false(如果没使用这个注解,则默认为true),就可以保证这个接口的缓存数据,在每次需要清理时都幸免于难

   @Expirable(false)
    Observable<Reply<User>> getCurrentUser(Observable<User> oUser, EvictProvider evictProvider);

值得注意的是: 构建RxCache时persistence方法传入的cacheDirectory,是用来存放RxCache本地缓存的文件夹,这个文件夹里最好不要有除RxCache之外的任何数据,这样会在每次需要遍历清理缓存时,节省不必要的开销,因为RxCache并没检查文件名,不管是不是自己的缓存,他都会去遍历获取

@SchemeMigration & @Migration

这两个注解是用来数据迁移的,用法:

@SchemeMigration({
            @Migration(version = 1, evictClasses = {Mock.class}),
            @Migration(version = 2, evictClasses = {Mock2.class})
    })
interface Providers {}

什么叫数据迁移呢?

简单的说就是在最新的版本中某个接口返回值类型内部发生了改变,从而获取数据的方式发生了改变,但是存储在本地的数据,是未改变的版本,这样在反序列化时就可能发生错误,为了规避这个风险,作者就加入了数据迁移的功能

有什么应用场景呢?

可能上面的话,不是很好理解,举个非常简单的例子:


public class Mock{
    private int id;
}

Mock里面有一个字段id,现在是一个整型int,能满足我们现在的需求,但是随着产品的迭代,发现int不够用了


public class Mock{
    private long id;
}

为了满足现在的需求,我们使用long代替int,由于缓存中的Mock还是之前未改变的版本,并且未过期,在使用本地缓存时会将数据反序列化,将int变为long,就会出现问题

数据迁移是怎么解决上面的问题呢?

其实非常简单,就是使用注解声明,之前有缓存并且内部修改过的class,RxCache会把含有这些class的缓存全部清除掉

RxCache是怎么操作的呢?

值得一提的是,在每次创建接口的动态代理时,也就是在每次调用RxCache.using(CacheProviders.class)时,会执行两个操作,清理含有@Migration中声明的evictClasses的缓存,以及遍历本地缓存文件夹清理所有已经过期的缓存

每次清理完需要数据迁移的缓存时,会将version值最大的@Migration的version值保存到本地

@SchemeMigration({
            @Migration(version = 1, evictClasses = {Mock.class}),
            @Migration(version = 3, evictClasses = {Mock3.class}),
            @Migration(version = 2, evictClasses = {Mock2.class})
    })
interface Providers {}

如上面的声明方式,它会将3保存到本地,每次调用using(),开始数据迁移时会将上次保存的version值从本地取出来,会在@SchemeMigration中查找大于这个version值的@Migration,取出里面evictClasses,去重后,遍历所有本地缓存,只要缓存数据中含有你声明的class,就将这个缓存清除

比如evictClasses中声明了Mock.class,会把以Observable< List< Mock >>,Observable< Map< String,Mock > >,Observable < Mock[] >或者Observable< Mock >作为返回值的接口缓存全部清理掉,然后在将最大version值记录到本地

所以每次有需要数据迁移的类时,必须在@SchemeMigration中添加新的@Migration,并且注解中version的值必须+1,这样才会达到数据迁移的效果

@SchemeMigration({
            @Migration(version = 1, evictClasses = {Mock.class}),
            @Migration(version = 3, evictClasses = {Mock3.class}),
            @Migration(version = 2, evictClasses = {Mock2.class}),
            @Migration(version = 4, evictClasses = {Mock2.class})

    })
interface Providers {}

如在上面的基础上,Mock2内部又发生改变,又需要数据迁移,就要新添加个@Migration,version = 4(3+1),这时在调用using()时只会将version = 4的@Migration中evictClasses声明的class进行数据迁移(即清理含有这个class的缓存数据)

@Actionable

这个注解在官方介绍中说明了会使用注解处理器给使用了这个注解的Interface,自动生成一个相同类名以Actionable结尾的类文件,使用这个类的APi方便更好的执行写操作,没使用过,不做过多介绍

总结

到这里RxCache的介绍就告一段落了,相信看完这篇文章后,基本使用肯定是没问题的

但是在使用中发现了一个问题,如果使用BaseResponse< T >,包裹数据的时候会出现错误,如issue$41和issue#73

分析问题

上面说了RxCache会将Retrofit返回的数据封装到Record对象里,Record会判断这个数据是那种类型,会先判断这个数据是否是Collection(List的父类),数组还是Map,如果都不是他会默认这个数据就是普通的对象

Record里有三个字段分别储存这个数据的,容器类名,容器里值的类名,和Map的Key类名,意思为如果数据类型为List< String >,容器类名为List,值类名为String,Key类名为空,如果数据类型为Map< String,Integer >,容器类名为Map,值类名为Integer,key类名为String

这三个字段的作用就是,在取本地缓存时可以使用Gson根据字段类型恢复真实数据的类型,问题就在这,因为使用的是BaseResponse< T >包裹数据,在上面的判断里,他排除了这个数据是List,数组或Map后它只会认定这个数据是普通的对象,这时他只会把三个字段里中值类名保存为BaseResponse其他则为空,范型的类型它并没通过字段记录,所以它在取的时候自然不会正确返回T的类型

解决问题

知道问题所在后,我们现在就来解决问题,解决这个问题现在有两个方向,一个是内部解决,一个是外部解决,外部解决的方式就可以通过上面issue#73所提到的方式

所谓内部解决就要改这个框架的内部代码了,问题就出在Record在数据为普通对象的时候,他不会使用字段保存范型的类型名,所以在取本地缓存的时候就无法正确恢复数据类型

解决的思路就是我们必须对数据为普通对象的时候做特殊处理,最简单的方式就是如果数据为对象时我们再判断instanceof BaseResponse,如果为true我们就重复做上面的判断

即判断BaseResponse中,T的类型是否为List,数组,Map还是对象?

然后在用对应的字段保存对应的类型名,取本地缓存的时候就可以用Gson按这些字段恢复正确的数据类型,但是这样强制的判断instanceof对于一个框架来说灵活性和扩展性会大打折扣,所以我后面写源码分析的时候会认真考虑下这个问题,可以的话我会Pull Request给Rxcache

- The end

基于Retrofit2,okhttp3的数据缓存(cache)技术(修改了缓存时间,能够设置缓存时间了) 可解决在无网络的情况下设置超时时间,之前很多文章可以实现在有网的情况下设置缓存时间,但是无网的情况下根本没有设置超时时间(设置是设置了,但是不起效果,大家可以测试) 当查找cache的时候,网上基本都是这样的文章,而且内容都这样;把里面的代码弄出来放到了包中,运行不了,真不知道疯狂转载类似文章的人是自己看了文章,实践了之后才疯狂转发的吗?不懂了!反正我是没能实现;然后看了我同学的这篇博客http://blog.youkuaiyun.com/qqyanjiang/article/details/51316116,看下来的感觉也差不多,问题同样没能解决,后来就问我同学了,然后他看了之后说少加了 立即下载

相关推荐

基于REasyHttp:xJava2+Retrofit2+RxCache的网络请求框架

目前网上对Rxjava2+Retrofit2的封装真是太多了,但是大体思路都是一样的,而且好多代码都具有相似性,这套其实也不例外,大家可选择性使用。  首先我们先不说封装思路,先说说这套框架都都具有哪些功能及如何使用; 功能 1 使用RxCache缓存机制,可自定义缓存过期时间,及数据分页缓存等功能。2 统一的请求错误处理;3 统一的网络状态判断处理;4 基于HttpLoggingInterceptor的请求日志打印。   以上就是这套框架可以实现的功能,框架中并没有像其他的一样封装了ProgressBar,因为每个项目不同,ProgressBar的样式需求并不一样,就算同一个项目中下拉刷新和普通加载可能也不一样,所以需要使用的小伙伴自己定义ProgressBar。  此外这套框架使用了RxCache实现缓存,而并不是通过OKHttp缓存,所以这套框架对服务器没有任何要求,不需要定义好Header之类的东西。

首席AI官(CAIO)如何破解企业AI战略落地难题

人工智能(AI)作为驱动数字化转型的核心技术,其原理在于通过算法模型从数据中学习规律,实现预测、决策和自动化。这项技术的价值在于能够显著提升运营效率、优化决策质量并创造新的业务模式。在企业级应用场景中,AI的规模化落地面临战略协同、投资管理、风险治理和人才建设等多重挑战。首席AI官(CAIO)这一新兴职位的设立,正是为了系统性地解决这些痛点,填补从技术试点到全面推广的领导力真空。CAIO作为战略制定者与价值实现负责人,需要具备深厚的技术判断力与广泛的商业洞察力,其核心职责在于统筹AI投资组合、建立治理框架并

weixin_33726313的博客 297

基于Android RxCache使用方法详解

前言 我为什么使用这个库? 事实上Android开发中缓存功能的实现选择有很多种,File缓存,SP缓存,或者数据库缓存,当然还有一些简单的库/工具类,比如github上的这个: 【ASimpleCache】:a simple cache for android and java 但是都不是很好用(虽然可能学习成本比较低,因为它使用起来相对简单),我可能需要很多的静态常量来作为key存储缓存数据value,并设置缓存的有效期,这可能需要很多Java代码去实现,并且过程繁琐。 如果您使用的网络请求库是Retrofit+RxJava,那么我推荐使用RxCache,正如作者所说的: RxCache

Cache-Control与retrofit缓存

Cache-Control HTTP中这个字段用于指定所有缓存机制在整个请求/响应链中必须服从的指令。缓存指令是单向的,即请求中存在一个指令并不意味着响应中将存在同一个指令。常见的取值有private、no-cache、max-age、must-revalidate等,默认为private。 常用 cache-directive 值 Cache-directive

hunter800421的专栏 3282

浅谈Android轻量级的数据缓存框架RxCache

本篇文章主要介绍了浅谈Android轻量级的数据缓存框架RxCache,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

A-Level CS 计算机科学 考试知识点——考试介绍&第1章

前言:该系列文章是本人在给学生辅导本课程的过程中结合英文教材所总结的,该系列共分为30章,主要介绍了考试的核心知识点。若需要A-Level CS 计算机科学考试辅导也可以私信我。 目录 关于A-Level CS 计算机科学考试 考试简介 考试内容 考试时间 评分情况 第1章 信息表示 本章学习内容 1.01 数字系统 1.02 数字的内部编码 整数编码(Coding for integers) 二进制编码的十进制(Binary coded decimal——BCD) 1.03.

王俊的博客 6458

Android RxCache使用详解

前言我为什么使用这个库?事实上Android开发中缓存功能的实现选择有很多种,File缓存,SP缓存,或者数据库缓存,当然还有一些简单的库/工具类,比如github上的这个:【ASimpleCache】:a simple cache for android and java但是都不是很好用(虽然可能学习成本比较低,因为它使用起来相对简单),我可能需要很多的静态常量来作为key存储缓存数据value,

却把清梅嗅的博客 6835

全桥LLC谐振变换器设计与双环控制策略详解

LLC谐振变换器作为高频开关电源的核心拓扑,通过谐振腔实现软开关特性,显著提升转换效率(可达96%以上)。其工作原理基于谐振电感、电容的协同作用,当开关频率接近谐振点时实现ZVS/ZCS。在工业电源、电动汽车充电等场景中,电压电流双环控制策略通过引入电流内环和竞争仲裁机制,有效改善动态响应(实测负载跳变时电压跌落减少60%)。数字控制实现时需注意ADC采样同步和PWM更新时序,而谐振参数测量与温升管理则是工程实践的关键。

weixin_29189987的博客 257

RxCache要点解读(四)

RxCache要点解读(四)RxCache好难呀。1.导入依赖包添加JitPack仓库在你的build.gradle文件 (项目根目录下):allprojects { repositories { jcenter() maven { url "https://jitpack.io" } } }添加依赖库,在项目模块中dependencies {

andayoung 1061

第四节、C# 上位机面向对象编程详解(工控硬件继承实战版)

继承核心价值:在 C# 上位机工控开发中,继承的核心是通用逻辑复用与接口统一,将所有硬件的通用属性 / 方法封装到抽象基类,子类只需实现独有逻辑,大幅减少冗余代码。基类设计要点:优先使用抽象基类,合理分配访问修饰符(privateprotectedpublic),定义通用事件与虚方法,提供资源释放机制,兼顾复用性与扩展性。子类设计要点:通过: base()调用基类构造函数,强制实现抽象方法(保证接口统一),选择性重写虚方法(实现独有逻辑),复用基类的protected成员。多设备管理。

kylezhao2019的博客 787

Halcon形状模板匹配实战:inspect_shape_model参数优化指南

本文深入解析Halcon形状模板匹配中inspect_shape_model参数的优化技巧,涵盖NumLevels和Contrast参数的实战应用。通过具体案例展示如何平衡匹配速度与精度,帮助开发者高效调试形状模型,提升工业视觉检测的准确性和效率。

weixin_30342209的博客 618

RxCache——Retrofit缓存库

RxCache——Retrofit缓存库 Retrofit是当下最火的网络请求库,其同门师兄网络请求库okhttp自带缓存,但是okhttp的缓存必须配合Header使用,比较麻烦,也不够灵活;对于Retrofit,RxCache是一款为其量身定制的缓存库。 RxCache使用注解来为Retrofit配置缓存信息,内部使用动态代理和Dagger来实现。Github官方教程:RxCache官方文档,...

weixin_38196407的博客 1045

泛微E9统一待办接口说明

需要第三方表单,在提交自己的流程后,通过【window.location.href=‘oa地址/workflow/request/ViewRequestOS.jsp?需要第三方表单,在提交自己的流程后,通过【window.location.href=‘oa地址/workflow/workflow/WfRefreshList.jsp’】通过中转页面与第三方系统对接,按照第三系统的验证方式开发中转页面中的程序。C)第三方根据相同的数据加密,结果一致就认证成功,打开流程。优点:可以灵活的对接各个系统。

泛微二次开发后端知识总结 6396

android retrofit缓存,RxJava+Retrofit2缓存库:RxCache中文文档

RxCache官方文档翻译本文翻译自:RxCache官方GitHub地址版本号:RxCache 1.8.1-2.xRxCache基本使用方法、Demo请参阅笔者的相关文章:概述本库的 目标 很简单: 就像Picasso 缓存您的图片一样,毫不费力缓存您的数据对象。每个Android Application都是一个客户端应用程序,这意味着仅仅为缓存数据创建数据库并进行维护毫无意义。事实上,传统方式通...

weixin_34530489的博客 675

Dify 第 19 篇 手把手教你开发 Dify 插件:从零实现一个时间工具

本文介绍了Dify平台的插件开发机制和流程。Dify支持多种插件类型,包括模型、工具、数据源等,可通过CLI工具快速开发插件。文章详细讲解了如何安装Dify CLI工具,并演示了从零开发一个获取系统时间插件的完整过程,包括项目初始化、文件解读和打包部署。通过该教程,开发者可以快速掌握Dify插件开发的核心要点,实现自定义功能扩展。

甘蓝的专栏 2448

光学材料仿真软件:FDTD Solutions_(4).材料属性的定义与应用

在光学材料仿真软件中,材料属性的定义和应用是至关重要的一步。正确地定义材料属性可以确保仿真结果的准确性和可靠性。本节将详细介绍如何在FDTD Solutions中定义和应用不同的材料属性,包括介质材料、金属材料、色散材料等,并提供具体的代码示例和数据样例。介质材料是光学仿真中最常见的材料类型之一。在FDTD Solutions中,可以通过多种方式定义介质材料,包括使用预定义的材料库、自定义材料参数或导入材料数据文件。FDTD Solutions内置了一个丰富的材料库,包含了许多常用材料的光学性质。

kkchenjj的博客 1401

RxCache 使用教程

RxCache 使用教程 1、项目介绍 RxCache 是一个专用于 RxJava 解决 Android 中对任何 Observable 发出的结果做缓存处理的框架。它支持多种缓存替换算法,如 FIFO、LRU 和 LFU,并且可以与 Retrofit 结合使用,提供高效的缓存解决方案。 2、项目快速启动 安装 首先,将 RxCache 添加到你的项目依赖中。在你的 build.gradle 文件...

gitblog_00566的博客 1015

【Docker安装】OpenEuler系统下部署Docker环境

【Docker安装】OpenEuler系统下部署Docker环境

jks212454的博客 4191

Retrofit 风格的 RxCache及其多种缓存替换算法

RxCache 是一个支持 Java 和 Android 的 Local Cache 。之前的文章《给 Java 和 Android 构建一个简单的响应式Local Ca...

Java与Android技术栈 289

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

retrofit 响应时间_RxCache一个用于 RxJava的缓存

RxCache 简单一步,缓存搞定。这是一个专用于 RxJava,解决 Android 中对任何 Observable 发出的结果做缓存处理的框架。 特性缓存层级Observable内存缓存 - LruCache磁盘缓存 - DiskLruCache目前已有的存储策略优先网络优先缓存优先缓存,并设置超时时间仅加载网络,但数据依然会被缓存先加载缓存,后加载网络仅加载网络,不缓存Getting sta...

weixin_42097508的博客 324

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

RxCache原理分析

RxCache配合retrofit使用的缓存方案 首先看一下rxcache的官方demo /** * 此为RxCache官方Demo */ public interface CacheProviders { @LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES) Observable<Reply<List<...

qq_29382145的博客 513

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Kotlin Android缓存库CoroutinesCache

RxJava+Retrofit如果想做缓存以前会用RxCache(停止维护). 迁移到Kotlin后,使用Coroutines+Retrofit请求网络想做缓存的话貌似资料还不是不多. CoroutinesCache 是用来做Coroutines+Retrofit缓存的,这个库Readme有点老,下面记录的是我使用的时候踩坑的笔记. 依赖 implementation "com.github.diefferson:CoroutinesCache:0.3.0" 使用 private val co.

碧云天丶 827

RxCache使用教程

以简单快捷的方式实现Android app实现网络数据缓存并不是一件容易的事 就像Sina微博Android客户端实现数据缓存离线阅读微博那样 这是一个基于 Retrofit的Reactive缓存库,可用于Android 和Java。能够将你的缓存成需求转成一个接口 配置 添加JitPack仓库在你的build.gradle文件 (项目根目录下): allprojec

windboy2014的博客 1万+
上一篇: 我们为什么要把Dagger2,MVP以及Rxjava引入项目中?
下一篇: 传统MVP用在项目中是真的方便还是累赘?
JessYanCoding
博客等级 码龄10年 63粉丝 15原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值