├── .gitignore ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── LICENSE ├── README.md ├── README_EN.md ├── app ├── .gitignore ├── build.gradle ├── key.jks ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── mock │ │ └── mock.json │ ├── java │ └── ren │ │ └── yale │ │ └── android │ │ └── retrofitcachetest │ │ ├── HttpResult.java │ │ ├── LogTestUtil.java │ │ ├── MainActivity.java │ │ ├── bean │ │ └── GankAndroid.java │ │ ├── rx1 │ │ ├── ApiRx1.java │ │ └── OKHttpUtilsRx1.java │ │ └── rx2 │ │ ├── ApiRx2.java │ │ └── OKHttpUtilsRx2.java │ └── res │ ├── layout │ └── activity_main.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── retrofitcachelib ├── .gitignore ├── LICENSE ├── build.gradle ├── config │ └── RetrofitCache.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── ren │ └── yale │ └── android │ └── retrofitcachelib │ ├── CacheInterceptorListener.java │ ├── MethodInfo.java │ ├── RetrofitCache.java │ ├── anno │ ├── Cache.java │ └── Mock.java │ ├── bean │ └── CacheConfig.java │ ├── intercept │ ├── BaseInterceptor.java │ ├── CacheForceInterceptorNoNet.java │ ├── CacheInterceptorOnNet.java │ └── MockInterceptor.java │ ├── transformer │ └── CacheTransformer.java │ └── util │ ├── LogUtil.java │ └── NetUtils.java ├── retrofitcachelibrx2 ├── .gitignore ├── build.gradle ├── config │ └── RetrofitCache.gradle ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── ren │ │ │ └── yale │ │ │ └── android │ │ │ └── retrofitcachelibrx2 │ │ │ ├── CacheInterceptorListener.java │ │ │ ├── MethodInfo.java │ │ │ ├── RetrofitCache.java │ │ │ ├── anno │ │ │ ├── Cache.java │ │ │ └── Mock.java │ │ │ ├── bean │ │ │ └── CacheConfig.java │ │ │ ├── intercept │ │ │ ├── BaseInterceptor.java │ │ │ ├── CacheForceInterceptorNoNet.java │ │ │ ├── CacheInterceptorOnNet.java │ │ │ └── MockInterceptor.java │ │ │ ├── transformer │ │ │ └── CacheTransformer.java │ │ │ └── util │ │ │ ├── LogUtil.java │ │ │ └── NetUtils.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── daoxuehao │ └── android │ └── retrofitcachelibrx2 │ └── ExampleUnitTest.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | src/main/res/ 11 | /.idea 12 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | - fork https://github.com/yale8848/RetrofitCache.git 2 | - git checkout **`dev`** 3 | - commit & push 4 | - pull request 5 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Mobile: 2 | 3 | Android OS: 4 | 5 | NetWork: 6 | 7 | URL: 8 | 9 | LIB Version: 10 | 11 | --- 12 | 13 | 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Yale 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RetrofitCache 2 | 3 | [English](README_EN.md) 4 | 5 | [![](https://img.shields.io/badge/jcenter-retrofitcache_1.1.1-519dd9.svg)](https://bintray.com/yale8848/maven/retrofitcache/1.1.1) 6 | [![](https://img.shields.io/badge/jcenter-retrofitcacherx2_1.1.1-519dd9.svg)](https://bintray.com/yale8848/maven/retrofitcacherx2/1.1.1) 7 | 8 | RetrofitCache让retrofit2+okhttp3+rxjava 配置缓存如此简单。通过注解配置,可以针对每一个接口灵活配置缓存策略;同时让每一个接口方便支持数据模拟,可以代码减小侵入性,模拟数据可以从内存,Assets,url轻松获取。 9 | 10 | ## 为什么使用RetrofitCache 11 | 12 | - 服务端接口不严格按照http缓存策略配置,有些不会针对每一个请求单独配置缓存策略 13 | - 第三方缓存库不是很方便的针对每一个接口进行缓存策略配置,侵入性比较大 14 | - 很方便的针对每个接口添加模拟数据 15 | 16 | ## 调用例子 17 | 18 | - 不走缓存例子 19 | 20 | ``` 21 | @GET("users") 22 | Observable test(); 23 | ``` 24 | 25 | - 缓存设置为20秒 26 | 27 | ``` 28 | @Cache(time = 20) 29 | @GET("users") 30 | Observable test(); 31 | ``` 32 | 33 | - 缓存设置为20分钟 34 | 35 | ``` 36 | @Cache(time = 20,timeUnit = TimeUnit.MINUTES) 37 | @GET("users") 38 | Observable test(); 39 | ``` 40 | 41 | - 默认时间缓存,默认是0秒 42 | 43 | ``` 44 | @Cache() 45 | @GET("users") 46 | Observable test(); 47 | ``` 48 | 49 | - 默认在无网的时候强制走缓存,forceCacheNoNet=false时无网络时不强制缓存 50 | 51 | ``` 52 | @Cache(forceCacheNoNet = false) 53 | @GET("users") 54 | Observable test(); 55 | ``` 56 | 57 | - 添加模拟数据(value,assets,url同时都配置的话,就按照这个顺序处理) 58 | 59 | ``` 60 | @Mock(value = "{\"data\":\"mockdata\"}") //模拟内存数据 61 | @GET("users") 62 | Observable test(); 63 | ``` 64 | 65 | ``` 66 | @Mock(assets = "mock/mock.json") //从assets获取模拟数据 67 | @GET("users") 68 | Observable test(); 69 | ``` 70 | 71 | ``` 72 | @Mock(url = "http://url.com/test") //从新的url请求数据 73 | @GET("users") 74 | Observable test(); 75 | ``` 76 | 77 | 78 | > 缓存只对http Get请求有效;如果要问为什么,可以问问后台开发同学 79 | 80 | ## 使用方法: 81 | 82 | - 添加 jcenter lib,注意根据自己的库选择 83 | 84 | ``` 85 | compile 'ren.yale.android:retrofitcachelib:1.1.1' //retrofit2+okhttp3+rxjava1 86 | compile 'ren.yale.android:retrofitcachelibrx2:1.1.1' //retrofit2+okhttp3+rxjava2 87 | ``` 88 | 89 | - 在Android Application里初始化 90 | 91 | ``` 92 | RetrofitCache.getInstance().init(this); 93 | ``` 94 | 95 | 也可以修改默认配置,默认time=0,timeUnit = TimeUnit.SECONDS 96 | 97 | ``` 98 | RetrofitCache.getInstance().init(this).setDefaultTimeUnit(TimeUnit.MINUTES).setDefaultTime(1); 99 | ``` 100 | 101 | - OkHttpClient初始化时配置缓存目录 102 | 103 | ``` 104 | okhttp3.OkHttpClient.Builder clientBuilder=new okhttp3.OkHttpClient.Builder(); 105 | ... 106 | int cacheSize = 200 * 1024 * 1024; 107 | File cacheDirectory = new File(mContext.getCacheDir(), "httpcache"); 108 | Cache cache = new Cache(cacheDirectory, cacheSize); 109 | OkHttpClient client = clientBuilder.cache(cache).build(); 110 | ... 111 | 112 | ``` 113 | 114 | - 给okhttp添加拦截器 115 | 116 | ``` 117 | okhttp3.OkHttpClient.Builder clientBuilder=new okhttp3.OkHttpClient.Builder(); 118 | ... 119 | 120 | //clientBuilder.addInterceptor(new MockInterceptor()); //如果只用Mock模拟功能,只需添加这个拦截器 121 | clientBuilder.addInterceptor(new CacheForceInterceptorNoNet()); 122 | clientBuilder.addNetworkInterceptor(new CacheInterceptorOnNet()); 123 | ... 124 | 125 | ``` 126 | 127 | > 添加CacheForceInterceptorNoNet作用是在无网时强制走缓存,如果只添加了CacheInterceptorOnNet,那么在有网和无网的缓存策略就会一样 128 | 129 | 130 | - 添加retrofit对象 131 | 132 | ``` 133 | Retrofit retrofit = new Retrofit.Builder() 134 | .baseUrl(url) 135 | .client(getOkHttpClient()) 136 | .addConverterFactory(GsonConverterFactory.create()) 137 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 138 | .build(); 139 | RetrofitCache.getInatance().addRetrofit(retrofit); 140 | ``` 141 | - **添加 rx Observable compose** 142 | 143 | ``` 144 | api.test().compose(CacheTransformer.emptyTransformer())... 145 | 146 | ``` 147 | 148 | 149 | ## 进阶 150 | 151 | 152 | - setCacheInterceptorListener 设置是否每一个接口都缓存 153 | 154 | ``` 155 | RetrofitCache.getInstance().setCacheInterceptorListener( 156 | new CacheInterceptorListener() { 157 | @Override 158 | public boolean canCache(Request request,Response response) { 159 | String res = ""; 160 | try { 161 | res = response.body().string(); 162 | } catch (IOException e) { 163 | e.printStackTrace(); 164 | } 165 | return true; 166 | } 167 | }); 168 | 169 | ``` 170 | 171 | 172 | - 设置是否走模拟数据,比如说在正式接口好了后可以如下设置,让模拟数据失效 173 | 174 | ``` 175 | RetrofitCache.getInstance().enableMock(false); 176 | ``` 177 | 178 | - 忽略某个参数;如果你对原url增加参数,可以设置忽略 179 | 180 | ``` 181 | RetrofitCache.getInstance().addIgnoreParam("access_token"); 182 | ``` 183 | 184 | 185 | ## 混淆配置(retrofit2+okhttp3+rxjava1) 186 | 187 | ``` 188 | -dontwarn ren.yale.android.retrofitcachelib.** 189 | -keep class ren.yale.android.retrofitcachelib.** { *; } 190 | -keepclasseswithmembernames class rx.Observable { *; } 191 | -keepclasseswithmembernames class rx.internal.operators.OnSubscribeLift { *; } 192 | -keepclasseswithmembernames class retrofit2.adapter.rxjava.RxJavaCallAdapterFactory { *; } 193 | -keepclasseswithmembernames class retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe { *; } 194 | -keepclasseswithmembernames class retrofit2.Retrofit { *; } 195 | -keepclasseswithmembernames class retrofit2.ServiceMethod { *; } 196 | -keepclasseswithmembernames class retrofit2.OkHttpCall { *; } 197 | 198 | ###retrofit2 2.5.0 199 | -keepclasseswithmembernames class retrofit2.HttpServiceMethod {*;} 200 | -keepclasseswithmembernames class retrofit2.RequestFactory {*;} 201 | 202 | #retrofit2,okhttp3,rxjava1等其它混淆配置请自行添加 203 | 204 | ``` 205 | ## 混淆配置(retrofit2+okhttp3+rxjava2) 206 | 207 | ``` 208 | -dontwarn ren.yale.android.retrofitcachelibrx2.** 209 | -keep class ren.yale.android.retrofitcachelibrx2.** { *; } 210 | -keepclasseswithmembernames class retrofit2.adapter.rxjava2.BodyObservable { *; } 211 | -keepclasseswithmembernames class retrofit2.adapter.rxjava2.ResultObservable { *; } 212 | -keepclasseswithmembernames class retrofit2.adapter.rxjava2.CallEnqueueObservable { *; } 213 | -keepclasseswithmembernames class retrofit2.adapter.rxjava2.CallExecuteObservable { *; } 214 | -keepclasseswithmembernames class retrofit2.Retrofit { *; } 215 | -keepclasseswithmembernames class retrofit2.ServiceMethod { *; } 216 | -keepclasseswithmembernames class retrofit2.OkHttpCall { *; } 217 | 218 | ###retrofit2 2.5.0 219 | -keepclasseswithmembernames class retrofit2.HttpServiceMethod {*;} 220 | -keepclasseswithmembernames class retrofit2.RequestFactory {*;} 221 | 222 | #retrofit2,okhttp3,rxjava2等其它混淆配置请自行添加 223 | 224 | ``` 225 | ## 欢迎提问讨论 226 | 227 | [讨论区](https://github.com/yale8848/RetrofitCache/issues) 228 | 229 | ## 贡献代码 230 | 231 | [贡献代码](CONTRIBUTING.md) 232 | 233 | ## 开源协议 234 | 235 | ``` 236 | MIT License 237 | 238 | Copyright (c) 2017 Yale 239 | 240 | Permission is hereby granted, free of charge, to any person obtaining a copy 241 | of this software and associated documentation files (the "Software"), to deal 242 | in the Software without restriction, including without limitation the rights 243 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 244 | copies of the Software, and to permit persons to whom the Software is 245 | furnished to do so, subject to the following conditions: 246 | 247 | The above copyright notice and this permission notice shall be included in all 248 | copies or substantial portions of the Software. 249 | 250 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 251 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 252 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 253 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 254 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 255 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 256 | SOFTWARE. 257 | ``` -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | # RetrofitCache 2 | 3 | [![](https://img.shields.io/badge/jcenter-retrofitcache_1.1.1-519dd9.svg)](https://bintray.com/yale8848/maven/retrofitcache/1.1.1) 4 | [![](https://img.shields.io/badge/jcenter-retrofitcacherx2_1.1.1-519dd9.svg)](https://bintray.com/yale8848/maven/retrofitcacherx2/1.1.1) 5 | 6 | RetrofitCache let retrofit2,okhttp3,rxjava add cache so easy. You can config cache strategy with each api by annotation.Also you can config mock data with each api easily. 7 | 8 | ## Why use? 9 | 10 | - Api server do not config http cache strategy 11 | - Third part lib config cache strategy not easy 12 | - Add mock data to each api very easily 13 | 14 | ## Demo 15 | 16 | - Not have cache 17 | 18 | ``` 19 | @GET("users") 20 | Observable test(); 21 | ``` 22 | 23 | - Cache time 20 seconds 24 | 25 | ``` 26 | @Cache(time = 20) 27 | @GET("users") 28 | Observable test(); 29 | ``` 30 | 31 | - Cache time 20 minutes 32 | 33 | ``` 34 | @Cache(time = 20,timeUnit = TimeUnit.MINUTES) 35 | @GET("users") 36 | Observable test(); 37 | ``` 38 | 39 | - Default cache time 0 seconds 40 | 41 | ``` 42 | @Cache() 43 | @GET("users") 44 | Observable test(); 45 | ``` 46 | 47 | - Default force cache without network, if forceCacheNoNet = false will break this rule 48 | 49 | ``` 50 | @Cache(forceCacheNoNet = false) 51 | @GET("users") 52 | Observable test(); 53 | ``` 54 | 55 | - Add mock data(if use value,assets,url same time, it will deal by this sort ) 56 | 57 | ``` 58 | @Mock(value = "{\"data\":\"mockdata\"}") //mock ram data 59 | @GET("users") 60 | Observable test(); 61 | ``` 62 | 63 | ``` 64 | @Mock(assets = "mock/mock.json") //mock data from assets 65 | @GET("users") 66 | Observable test(); 67 | ``` 68 | 69 | ``` 70 | @Mock(url = "http://url.com/test") //mock data from new url 71 | @GET("users") 72 | Observable test(); 73 | ``` 74 | 75 | 76 | > Cache just with http Get method 77 | 78 | ## How to use 79 | 80 | - Add jcenter lib,notice chose different with you project 81 | 82 | ``` 83 | compile 'ren.yale.android:retrofitcachelib:1.1.1' //retrofit2+okhttp3+rxjava1 84 | compile 'ren.yale.android:retrofitcachelibrx2:1.1.1' //retrofit2+okhttp3+rxjava2 85 | ``` 86 | 87 | - Init in Android Application 88 | 89 | ``` 90 | RetrofitCache.getInstance().init(this); 91 | ``` 92 | 93 | Also can modify default config, default value time=0,timeUnit = TimeUnit.SECONDS 94 | 95 | ``` 96 | RetrofitCache.getInstance().init(this).setDefaultTimeUnit(TimeUnit.MINUTES).setDefaultTime(1); 97 | ``` 98 | 99 | - OkHttpClient config cache dir 100 | 101 | ``` 102 | okhttp3.OkHttpClient.Builder clientBuilder=new okhttp3.OkHttpClient.Builder(); 103 | ... 104 | int cacheSize = 200 * 1024 * 1024; 105 | File cacheDirectory = new File(mContext.getCacheDir(), "httpcache"); 106 | Cache cache = new Cache(cacheDirectory, cacheSize); 107 | OkHttpClient client = clientBuilder.cache(cache).build(); 108 | ... 109 | 110 | ``` 111 | 112 | - okhttp add Interceptor 113 | 114 | ``` 115 | okhttp3.OkHttpClient.Builder clientBuilder=new okhttp3.OkHttpClient.Builder(); 116 | ... 117 | 118 | //clientBuilder.addInterceptor(new MockInterceptor()); //Only add this interceptor if only use Mock 119 | clientBuilder.addInterceptor(new CacheForceInterceptorNoNet()); 120 | clientBuilder.addNetworkInterceptor(new CacheInterceptorOnNet()); 121 | ... 122 | 123 | ``` 124 | 125 | 126 | - Add retrofit object 127 | 128 | ``` 129 | Retrofit retrofit = new Retrofit.Builder() 130 | .baseUrl(url) 131 | .client(getOkHttpClient()) 132 | .addConverterFactory(GsonConverterFactory.create()) 133 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 134 | .build(); 135 | RetrofitCache.getInstance().addRetrofit(retrofit); 136 | ``` 137 | - **Add rx Observable compose** 138 | 139 | ``` 140 | api.test().compose(CacheTransformer.emptyTransformer())... 141 | 142 | ``` 143 | 144 | 145 | ## Further 146 | 147 | 148 | - setCacheInterceptorListener to set whether can cache by each api 149 | 150 | ``` 151 | RetrofitCache.getInstance().setCacheInterceptorListener( 152 | new CacheInterceptorListener() { 153 | @Override 154 | public boolean canCache(Request request,Response response) { 155 | String res = ""; 156 | try { 157 | res = response.body().string(); 158 | } catch (IOException e) { 159 | e.printStackTrace(); 160 | } 161 | return true; 162 | } 163 | }); 164 | 165 | ``` 166 | 167 | 168 | - Enable mock data , if your release api ok,you can set false 169 | 170 | ``` 171 | RetrofitCache.getInstance().enableMock(false); 172 | ``` 173 | - Ignore some param. If you add some param in url, you can call addIgnoreParam. 174 | 175 | ``` 176 | RetrofitCache.getInstance().addIgnoreParam("access_token"); 177 | ``` 178 | 179 | ## Proguard 180 | 181 | ``` 182 | -keepattributes *Annotation*,InnerClasses 183 | 184 | -dontwarn ren.yale.android.retrofitcachelib.** 185 | -keep class ren.yale.android.retrofitcachelib.** { *; } 186 | 187 | #retrofit2 188 | -dontwarn retrofit2.** 189 | -keep class retrofit2.** { *; } 190 | -keepattributes Signature 191 | -keepattributes Exceptions 192 | 193 | -dontwarn org.robovm.** 194 | -keep class org.robovm.** { *; } 195 | 196 | #okhttp3 197 | -dontwarn com.squareup.okhttp3.** 198 | -keep class com.squareup.okhttp3.** { *;} 199 | -keep class okhttp3.** { *;} 200 | -keep class okio.** { *;} 201 | -dontwarn sun.security.** 202 | -keep class sun.security.** { *;} 203 | -dontwarn okio.** 204 | -dontwarn okhttp3.** 205 | 206 | #rxjava 207 | -dontwarn rx.** 208 | -keep class rx.** { *; } 209 | 210 | -dontwarn sun.misc.** 211 | -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* { 212 | long producerIndex; 213 | long consumerIndex; 214 | } 215 | -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef { 216 | rx.internal.util.atomic.LinkedQueueNode producerNode; 217 | } 218 | -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef { 219 | rx.internal.util.atomic.LinkedQueueNode consumerNode; 220 | } 221 | 222 | ``` 223 | 224 | 225 | ## Proguard(retrofit2+okhttp3+rxjava1) 226 | 227 | ``` 228 | -dontwarn ren.yale.android.retrofitcachelib.** 229 | -keep class ren.yale.android.retrofitcachelib.** { *; } 230 | -keepclasseswithmembernames class rx.Observable { *; } 231 | -keepclasseswithmembernames class rx.internal.operators.OnSubscribeLift { *; } 232 | -keepclasseswithmembernames class retrofit2.adapter.rxjava.RxJavaCallAdapterFactory { *; } 233 | -keepclasseswithmembernames class retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe { *; } 234 | -keepclasseswithmembernames class retrofit2.Retrofit { *; } 235 | -keepclasseswithmembernames class retrofit2.ServiceMethod { *; } 236 | -keepclasseswithmembernames class retrofit2.OkHttpCall { *; } 237 | 238 | ###retrofit2 2.5.0 239 | -keepclasseswithmembernames class retrofit2.HttpServiceMethod {*;} 240 | -keepclasseswithmembernames class retrofit2.RequestFactory {*;} 241 | 242 | #retrofit2,okhttp3,rxjava1 and other Proguard config add by yourself 243 | 244 | ``` 245 | ## Proguard(retrofit2+okhttp3+rxjava2) 246 | 247 | ``` 248 | -dontwarn ren.yale.android.retrofitcachelibrx2.** 249 | -keep class ren.yale.android.retrofitcachelibrx2.** { *; } 250 | -keepclasseswithmembernames class retrofit2.adapter.rxjava2.BodyObservable { *; } 251 | -keepclasseswithmembernames class retrofit2.adapter.rxjava2.ResultObservable { *; } 252 | -keepclasseswithmembernames class retrofit2.adapter.rxjava2.CallEnqueueObservable { *; } 253 | -keepclasseswithmembernames class retrofit2.adapter.rxjava2.CallExecuteObservable { *; } 254 | -keepclasseswithmembernames class retrofit2.Retrofit { *; } 255 | -keepclasseswithmembernames class retrofit2.ServiceMethod { *; } 256 | -keepclasseswithmembernames class retrofit2.OkHttpCall { *; } 257 | 258 | ###retrofit2 2.5.0 259 | -keepclasseswithmembernames class retrofit2.HttpServiceMethod {*;} 260 | -keepclasseswithmembernames class retrofit2.RequestFactory {*;} 261 | 262 | #retrofit2,okhttp3,rxjava2 and other Proguard config add by yourself 263 | 264 | ``` 265 | 266 | 267 | ## Issues 268 | 269 | [Issues](https://github.com/yale8848/RetrofitCache/issues) 270 | 271 | ## How CONTRIBUTING 272 | 273 | [CONTRIBUTING](CONTRIBUTING.md) 274 | 275 | ## License 276 | 277 | ``` 278 | MIT License 279 | 280 | Copyright (c) 2017 Yale 281 | 282 | Permission is hereby granted, free of charge, to any person obtaining a copy 283 | of this software and associated documentation files (the "Software"), to deal 284 | in the Software without restriction, including without limitation the rights 285 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 286 | copies of the Software, and to permit persons to whom the Software is 287 | furnished to do so, subject to the following conditions: 288 | 289 | The above copyright notice and this permission notice shall be included in all 290 | copies or substantial portions of the Software. 291 | 292 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 293 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 294 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 295 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 296 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 297 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 298 | SOFTWARE. 299 | ``` -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | buildToolsVersion "28.0.3" 6 | useLibrary 'org.apache.http.legacy' 7 | defaultConfig { 8 | applicationId "ren.yale.android.retrofitcachetest" 9 | minSdkVersion 14 10 | targetSdkVersion 22 11 | versionCode 1 12 | versionName "1.0" 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 14 | } 15 | 16 | signingConfigs { 17 | 18 | 19 | release { 20 | storeFile file("key.jks") 21 | storePassword "123456" 22 | keyAlias "key0" 23 | keyPassword "123456" 24 | v2SigningEnabled false 25 | v1SigningEnabled true 26 | } 27 | } 28 | buildTypes { 29 | debug { 30 | signingConfig signingConfigs.release 31 | minifyEnabled false 32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 33 | } 34 | release { 35 | signingConfig signingConfigs.release 36 | minifyEnabled true 37 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 38 | } 39 | } 40 | packagingOptions { 41 | exclude 'META-INF/rxjava.properties' 42 | } 43 | } 44 | 45 | dependencies { 46 | 47 | 48 | 49 | 50 | //implementation 'ren.yale.android:retrofitcachelib:1.1.1' //retrofit2+okhttp3+rxjava1 51 | //implementation 'ren.yale.android:retrofitcachelibrx2:1.1.1' //retrofit2+okhttp3+rxjava2 52 | 53 | 54 | implementation project(':retrofitcachelib') 55 | implementation 'io.reactivex:rxandroid:1.2.1' 56 | implementation 'com.squareup.retrofit2:converter-gson:2.1.0' 57 | implementation 'com.squareup.okio:okio:1.11.0' 58 | implementation 'com.squareup.retrofit2:adapter-rxjava:2.1.0' 59 | 60 | 61 | implementation project(':retrofitcachelibrx2') 62 | implementation'io.reactivex.rxjava2:rxjava:2.0.7' 63 | implementation'io.reactivex.rxjava2:rxandroid:2.0.1' 64 | implementation'com.squareup.retrofit2:retrofit:2.5.0' 65 | implementation'com.squareup.retrofit2:converter-gson:2.2.0' 66 | implementation'com.squareup.retrofit2:adapter-rxjava2:2.2.0' 67 | 68 | 69 | implementation 'com.alibaba:fastjson:1.1.55.android' 70 | } 71 | -------------------------------------------------------------------------------- /app/key.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yale8848/RetrofitCache/4d6a641d9d53a09e3d76ae7d588f6bf612a0d05c/app/key.jks -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | 2 | -dontwarn ren.yale.android.retrofitcachelib.** 3 | -keep class ren.yale.android.retrofitcachelib.** { *; } 4 | -keepclasseswithmembernames class rx.Observable { *; } 5 | -keepclasseswithmembernames class rx.internal.operators.OnSubscribeLift { *; } 6 | -keepclasseswithmembernames class retrofit2.adapter.rxjava.RxJavaCallAdapterFactory { *; } 7 | -keepclasseswithmembernames class retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe { *; } 8 | 9 | -keepclasseswithmembernames class retrofit2.Retrofit { *; } 10 | -keepclasseswithmembernames class retrofit2.ServiceMethod { *; } 11 | -keepclasseswithmembernames class retrofit2.OkHttpCall { *; } 12 | 13 | 14 | -dontwarn ren.yale.android.retrofitcachelibrx2.** 15 | -keep class ren.yale.android.retrofitcachelibrx2.** { *; } 16 | -keepclasseswithmembernames class retrofit2.adapter.rxjava2.BodyObservable { *; } 17 | -keepclasseswithmembernames class retrofit2.adapter.rxjava2.ResultObservable { *; } 18 | -keepclasseswithmembernames class retrofit2.adapter.rxjava2.CallEnqueueObservable { *; } 19 | -keepclasseswithmembernames class retrofit2.adapter.rxjava2.CallExecuteObservable { *; } 20 | 21 | 22 | 23 | #retrofit2 24 | -dontwarn retrofit2.** 25 | #-keep class retrofit2.** { *; } 26 | 27 | 28 | 29 | 30 | -keepattributes Signature 31 | -keepattributes Exceptions 32 | 33 | -dontwarn org.robovm.** 34 | #-keep class org.robovm.** { *; } 35 | 36 | #okhttp3 37 | -dontwarn com.squareup.okhttp3.** 38 | #-keep class okhttp3.internal.**{*;} 39 | #-keep class com.squareup.okhttp3.** { *;} 40 | #-keep class okhttp3.** { *;} 41 | #-keep class okio.** { *;} 42 | -dontwarn sun.security.** 43 | -keep class sun.security.** { *;} 44 | -dontwarn okio.** 45 | -dontwarn okhttp3.** 46 | 47 | #rxjava 48 | -dontwarn rx.** 49 | #-keep class rx.** { *; } 50 | 51 | 52 | -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* { 53 | long producerIndex; 54 | long consumerIndex; 55 | } 56 | -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef { 57 | rx.internal.util.atomic.LinkedQueueNode producerNode; 58 | } 59 | -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef { 60 | rx.internal.util.atomic.LinkedQueueNode consumerNode; 61 | } 62 | 63 | # Gson 64 | #-keep class com.google.gson.stream.** { *; } 65 | #-keepattributes EnclosingMethod 66 | 67 | #APP 68 | 69 | -keep class ren.yale.android.retrofitcachetest.** { *; } 70 | 71 | #-------------------------------------------基本不用动区域-------------------------------------------- 72 | #---------------------------------基本指令区---------------------------------- 73 | -optimizationpasses 5 74 | -dontskipnonpubliclibraryclassmembers 75 | -printmapping proguardMapping.txt 76 | -optimizations !code/simplification/cast,!field/*,!class/merging/* 77 | -keepattributes *Annotation*,InnerClasses 78 | -keepattributes Signature 79 | -keepattributes SourceFile,LineNumberTable 80 | #-ignorewarnings 81 | #---------------------------------------------------------------------------- 82 | 83 | #---------------------------------默认保留区--------------------------------- 84 | -keep public class * extends android.app.Activity 85 | -keep public class * extends android.app.Application 86 | -keep public class * extends android.app.Service 87 | -keep public class * extends android.content.BroadcastReceiver 88 | -keep public class * extends android.content.ContentProvider 89 | -keep public class * extends android.app.backup.BackupAgentHelper 90 | -keep public class * extends android.preference.Preference 91 | -keep public class * extends android.view.View 92 | -keep public class com.android.vending.licensing.ILicensingService 93 | -keep class android.support.** {*;} 94 | -keep public class * extends android.os.IInterface 95 | 96 | -keep public class * extends android.view.View{ 97 | *** get*(); 98 | void set*(***); 99 | public (android.content.Context); 100 | public (android.content.Context, android.util.AttributeSet); 101 | public (android.content.Context, android.util.AttributeSet, int); 102 | } 103 | -keepclasseswithmembers class * { 104 | public (android.content.Context, android.util.AttributeSet); 105 | public (android.content.Context, android.util.AttributeSet, int); 106 | } 107 | -keepclassmembers class * implements java.io.Serializable { 108 | static final long serialVersionUID; 109 | private static final java.io.ObjectStreamField[] serialPersistentFields; 110 | private void writeObject(java.io.ObjectOutputStream); 111 | private void readObject(java.io.ObjectInputStream); 112 | java.lang.Object writeReplace(); 113 | java.lang.Object readResolve(); 114 | } 115 | -keep class **.R$* { 116 | *; 117 | } 118 | -keepclassmembers class * { 119 | void *(**On*Event); 120 | } 121 | 122 | -keepclasseswithmembernames class * { # 保持 native 方法不被混淆 123 | native ; 124 | } 125 | 126 | -keepclasseswithmembers class * { # 保持自定义控件类不被混淆 127 | public (android.content.Context, android.util.AttributeSet); 128 | } 129 | 130 | -keepclasseswithmembers class * {# 保持自定义控件类不被混淆 131 | public (android.content.Context, android.util.AttributeSet, int); 132 | } 133 | 134 | -keepclassmembers class * extends android.app.Activity { # 保持自定义控件类不被混淆 135 | public void *(android.view.View); 136 | } 137 | 138 | -keepclassmembers enum * { # 保持枚举 enum 类不被混淆 139 | public static **[] values(); 140 | public static ** valueOf(java.lang.String); 141 | } 142 | 143 | -keep class * implements android.os.Parcelable { # 保持 Parcelable 不被混淆 144 | public static final android.os.Parcelable$Creator *; 145 | } 146 | 147 | #---------------------------------------------------------------------------- 148 | 149 | #---------------------------------webview------------------------------------ 150 | -keepclassmembers class fqcn.of.javascript.interface.for.webview { 151 | public *; 152 | } 153 | -keepclassmembers class * extends android.webkit.webViewClient { 154 | public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap); 155 | public boolean *(android.webkit.WebView, java.lang.String); 156 | } 157 | -keepclassmembers class * extends android.webkit.webViewClient { 158 | public void *(android.webkit.webView, jav.lang.String); 159 | } 160 | #---------------------------------------------------------------------------- 161 | #--------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/assets/mock/mock.json: -------------------------------------------------------------------------------- 1 | {"error":false,"results":[{"_id":"5941f5f3421aa92c7be61c16","createdAt":"2017-06-15T10:50:27.317Z","desc":"1111111\\u4effNice\\u9996\\u9875\\u56fe\\u7247\\u5217\\u88689\\u56fe\\u6837\\u5f0f\\uff0c\\u5e76\\u5b9e\\u73b0\\u62d6\\u62fd\\u6548\\u679c","images":["http://img.gank.io/4f54c011-e293-436a-ada1-dc03669ffb10"],"publishedAt":"2017-06-15T13:55:57.947Z","source":"web","type":"Android","url":"http://www.jianshu.com/p/0ea96b952170","used":true,"who":"wwweee的事发生飞洒地方bbb"}]} -------------------------------------------------------------------------------- /app/src/main/java/ren/yale/android/retrofitcachetest/HttpResult.java: -------------------------------------------------------------------------------- 1 | package ren.yale.android.retrofitcachetest; 2 | 3 | /** 4 | * Created by Yale on 2017/6/13. 5 | */ 6 | 7 | public class HttpResult { 8 | private String message=""; 9 | private boolean success = false; 10 | 11 | public String getMessage() { 12 | return message; 13 | } 14 | 15 | public void setMessage(String message) { 16 | this.message = message; 17 | } 18 | 19 | public boolean isSuccess() { 20 | return success; 21 | } 22 | 23 | public void setSuccess(boolean success) { 24 | this.success = success; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/ren/yale/android/retrofitcachetest/LogTestUtil.java: -------------------------------------------------------------------------------- 1 | package ren.yale.android.retrofitcachetest; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * Created by yale on 2017/11/29. 7 | */ 8 | 9 | public class LogTestUtil { 10 | private static String TAG="retrofitcache"; 11 | public static void d(String text){ 12 | Log.d(TAG,text); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/ren/yale/android/retrofitcachetest/MainActivity.java: -------------------------------------------------------------------------------- 1 | package ren.yale.android.retrofitcachetest; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.widget.TextView; 7 | 8 | import com.alibaba.fastjson.JSON; 9 | 10 | import io.reactivex.Observer; 11 | import io.reactivex.disposables.Disposable; 12 | import io.reactivex.subjects.Subject; 13 | import ren.yale.android.retrofitcachelib.RetrofitCache; 14 | import ren.yale.android.retrofitcachetest.bean.GankAndroid; 15 | import ren.yale.android.retrofitcachetest.rx1.OKHttpUtilsRx1; 16 | import ren.yale.android.retrofitcachetest.rx2.OKHttpUtilsRx2; 17 | import rx.Subscriber; 18 | 19 | public class MainActivity extends Activity { 20 | 21 | private TextView mTextView; 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | 26 | OKHttpUtilsRx1.INSTANCE.init(this.getApplication()); 27 | OKHttpUtilsRx2.INSTANCE.init(this.getApplication()); 28 | RetrofitCache.getInstance().init(this).enableMock(true); 29 | RetrofitCache.getInstance().addIgnoreParam("access_token"); 30 | setContentView(R.layout.activity_main); 31 | mTextView = (TextView) findViewById(R.id.tv_content); 32 | } 33 | 34 | private void testRx1(){ 35 | OKHttpUtilsRx1.INSTANCE.getApi().getGankAndroid("bb") 36 | .compose(OKHttpUtilsRx1.IoMain()) 37 | .subscribe(new Subscriber() { 38 | @Override 39 | public void onStart() { 40 | mTextView.setText(""); 41 | } 42 | 43 | @Override 44 | public void onCompleted() { 45 | } 46 | @Override 47 | public void onError(Throwable e) { 48 | 49 | e.printStackTrace(); 50 | } 51 | @Override 52 | public void onNext(GankAndroid gankAndroid) { 53 | mTextView.setText(JSON.toJSONString(gankAndroid)); 54 | } 55 | }); 56 | } 57 | private void testRx1RamMock(){ 58 | OKHttpUtilsRx1.INSTANCE.getApi().getRamMockGankAndroid() 59 | .compose(OKHttpUtilsRx1.IoMain()) 60 | .subscribe(new Subscriber() { 61 | @Override 62 | public void onStart() { 63 | mTextView.setText(""); 64 | } 65 | 66 | @Override 67 | public void onCompleted() { 68 | } 69 | @Override 70 | public void onError(Throwable e) { 71 | 72 | e.printStackTrace(); 73 | } 74 | @Override 75 | public void onNext(GankAndroid gankAndroid) { 76 | mTextView.setText(JSON.toJSONString(gankAndroid)); 77 | } 78 | }); 79 | } 80 | private void testRx1UrlMock(){ 81 | OKHttpUtilsRx1.INSTANCE.getApi().getUrlMockGankAndroid() 82 | .compose(OKHttpUtilsRx1.IoMain()) 83 | .subscribe(new Subscriber() { 84 | @Override 85 | public void onStart() { 86 | mTextView.setText(""); 87 | } 88 | 89 | @Override 90 | public void onCompleted() { 91 | } 92 | @Override 93 | public void onError(Throwable e) { 94 | 95 | e.printStackTrace(); 96 | } 97 | @Override 98 | public void onNext(GankAndroid gankAndroid) { 99 | mTextView.setText(JSON.toJSONString(gankAndroid)); 100 | } 101 | }); 102 | } 103 | private void testRx2(){ 104 | OKHttpUtilsRx2.INSTANCE.getApi().getGankAndroid() 105 | .compose(OKHttpUtilsRx2.INSTANCE.IoMain()) 106 | .subscribe(new Subject() { 107 | @Override 108 | public boolean hasObservers() { 109 | return false; 110 | } 111 | 112 | @Override 113 | public boolean hasThrowable() { 114 | return false; 115 | } 116 | 117 | @Override 118 | public boolean hasComplete() { 119 | return false; 120 | } 121 | 122 | @Override 123 | public Throwable getThrowable() { 124 | return null; 125 | } 126 | 127 | @Override 128 | protected void subscribeActual(Observer observer) { 129 | 130 | } 131 | 132 | @Override 133 | public void onSubscribe(Disposable d) { 134 | 135 | } 136 | 137 | @Override 138 | public void onNext(GankAndroid gankAndroid) { 139 | mTextView.setText(JSON.toJSONString(gankAndroid)); 140 | } 141 | 142 | @Override 143 | public void onError(Throwable e) { 144 | 145 | } 146 | 147 | @Override 148 | public void onComplete() { 149 | 150 | } 151 | }); 152 | } 153 | private void testRx1AsssetslMock(){ 154 | OKHttpUtilsRx1.INSTANCE.getApi().getAssetsMockGankAndroid() 155 | .compose(OKHttpUtilsRx1.IoMain()) 156 | .subscribe(new Subscriber() { 157 | @Override 158 | public void onStart() { 159 | mTextView.setText(""); 160 | } 161 | 162 | @Override 163 | public void onCompleted() { 164 | } 165 | @Override 166 | public void onError(Throwable e) { 167 | 168 | e.printStackTrace(); 169 | } 170 | @Override 171 | public void onNext(GankAndroid gankAndroid) { 172 | mTextView.setText(JSON.toJSONString(gankAndroid)); 173 | } 174 | }); 175 | } 176 | public void onClickRx1AssetsMock(View v){ 177 | testRx1AsssetslMock(); 178 | } 179 | public void onClickRx1(View v){ 180 | 181 | testRx1(); 182 | } 183 | public void onClickRx1RamMock(View v){ 184 | testRx1RamMock(); 185 | } 186 | public void onClickRx1UrlMock(View v){ 187 | testRx1UrlMock(); 188 | } 189 | public void onClickRx2(View v){ 190 | mTextView.setText(""); 191 | testRx2(); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /app/src/main/java/ren/yale/android/retrofitcachetest/bean/GankAndroid.java: -------------------------------------------------------------------------------- 1 | package ren.yale.android.retrofitcachetest.bean; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by Yale on 2017/7/5. 7 | */ 8 | 9 | public class GankAndroid { 10 | 11 | /** 12 | * error : false 13 | * results : [{"_id":"595ad074421aa90ca3bb6a90","createdAt":"2017-07-04T07:17:08.609Z","desc":"Android 有两套相机 ApiRx1,使用起来很麻烦,好在 Foto 开源了他们在 Android 上的 Camera 封装 ApiRx1,力荐!","images":["http://img.gank.io/0a15bae7-c513-4feb-bbe2-1273b8b809ce"],"publishedAt":"2017-07-04T11:50:36.484Z","source":"chrome","type":"Android","url":"https://github.com/Fotoapparat/Fotoapparat","used":true,"who":"代码家"},{"_id":"595ad096421aa90cb4724b5b","createdAt":"2017-07-04T07:17:42.635Z","desc":"MD 风格的日历组件,很精致哦。","images":["http://img.gank.io/75a6251f-ffaf-41dc-8dbc-fa58802b0d8e"],"publishedAt":"2017-07-04T11:50:36.484Z","source":"chrome","type":"Android","url":"https://github.com/Applandeo/Material-Calendar-View","used":true,"who":"代码家"},{"_id":"595ad0d4421aa90cb4724b5c","createdAt":"2017-07-04T07:18:44.154Z","desc":"非常 Fancy 的选项过滤器。","images":["http://img.gank.io/f9e1e0ef-88fc-4e02-8620-2cf1700966c5"],"publishedAt":"2017-07-04T11:50:36.484Z","source":"chrome","type":"Android","url":"https://github.com/Krupen/FabulousFilter","used":true,"who":"代码家"},{"_id":"595aec75421aa90c9203d31c","createdAt":"2017-07-04T09:16:37.902Z","desc":"Android单元测试框架Robolectric3.0(二):数据篇","publishedAt":"2017-07-04T11:50:36.484Z","source":"web","type":"Android","url":"http://url.cn/4BHx7ZG","used":true,"who":"陈宇明"},{"_id":"595b0bed421aa90ca3bb6a98","createdAt":"2017-07-04T11:30:53.793Z","desc":"前端每周清单第 20 期:React 组件解耦之道;基于Headless Chrome的自动化测试;Angular 2/4是否为时已晚?","publishedAt":"2017-07-04T11:50:36.484Z","source":"chrome","type":"Android","url":"https://zhuanlan.zhihu.com/p/27684971","used":true,"who":"王下邀月熊"},{"_id":"595b0f5a421aa90cb4724b60","createdAt":"2017-07-04T11:45:30.184Z","desc":"Android App Performance Optimization","publishedAt":"2017-07-04T11:50:36.484Z","source":"web","type":"Android","url":"https://blog.mindorks.com/android-app-performance-optimization-cdccb422e38e","used":true,"who":"AMIT SHEKHAR"},{"_id":"593f2091421aa92c769a8c6a","createdAt":"2017-06-13T07:15:29.423Z","desc":"Android之自定义View:侧滑删除","publishedAt":"2017-06-15T13:55:57.947Z","source":"web","type":"Android","url":"https://mp.weixin.qq.com/s?__biz=MzIwMzYwMTk1NA==&mid=2247484934&idx=1&sn=f2a40261efe8ebee45804e9df93c1cce&chksm=96cda74ba1ba2e5dbbac15a9e57b5329176d1fe43478e5c63f7bc502a6ca50e4dfa6c0a9041e#rd","used":true,"who":"陈宇明"},{"_id":"594109e5421aa92c769a8c84","createdAt":"2017-06-14T18:03:17.393Z","desc":"RecyclerView:利用打造悬浮效果","images":["http://img.gank.io/775b8ae5-4c21-4553-a77e-a0842248e1af"],"publishedAt":"2017-06-15T13:55:57.947Z","source":"web","type":"Android","url":"http://www.jianshu.com/p/b335b620af39","used":true,"who":null},{"_id":"5941e2ac421aa92c7be61c14","createdAt":"2017-06-15T09:28:12.702Z","desc":"《From Java To Kotlin》从Java到Kotlin·译 (双语对比)","publishedAt":"2017-06-15T13:55:57.947Z","source":"web","type":"Android","url":"http://url.cn/4AS5wCG","used":true,"who":"陈宇明"},{"_id":"5941f5f3421aa92c7be61c16","createdAt":"2017-06-15T10:50:27.317Z","desc":"仿Nice首页图片列表9图样式,并实现拖拽效果","images":["http://img.gank.io/4f54c011-e293-436a-ada1-dc03669ffb10"],"publishedAt":"2017-06-15T13:55:57.947Z","source":"web","type":"Android","url":"http://www.jianshu.com/p/0ea96b952170","used":true,"who":"兔子吃过窝边草"}] 14 | */ 15 | 16 | private boolean error; 17 | private List results; 18 | 19 | public boolean isError() { 20 | return error; 21 | } 22 | 23 | public void setError(boolean error) { 24 | this.error = error; 25 | } 26 | 27 | public List getResults() { 28 | return results; 29 | } 30 | 31 | public void setResults(List results) { 32 | this.results = results; 33 | } 34 | 35 | public static class ResultsBean { 36 | /** 37 | * _id : 595ad074421aa90ca3bb6a90 38 | * createdAt : 2017-07-04T07:17:08.609Z 39 | * desc : Android 有两套相机 ApiRx1,使用起来很麻烦,好在 Foto 开源了他们在 Android 上的 Camera 封装 ApiRx1,力荐! 40 | * images : ["http://img.gank.io/0a15bae7-c513-4feb-bbe2-1273b8b809ce"] 41 | * publishedAt : 2017-07-04T11:50:36.484Z 42 | * source : chrome 43 | * type : Android 44 | * url : https://github.com/Fotoapparat/Fotoapparat 45 | * used : true 46 | * who : 代码家 47 | */ 48 | 49 | private String _id; 50 | private String createdAt; 51 | private String desc; 52 | private String publishedAt; 53 | private String source; 54 | private String type; 55 | private String url; 56 | private boolean used; 57 | private String who; 58 | private List images; 59 | 60 | public String get_id() { 61 | return _id; 62 | } 63 | 64 | public void set_id(String _id) { 65 | this._id = _id; 66 | } 67 | 68 | public String getCreatedAt() { 69 | return createdAt; 70 | } 71 | 72 | public void setCreatedAt(String createdAt) { 73 | this.createdAt = createdAt; 74 | } 75 | 76 | public String getDesc() { 77 | return desc; 78 | } 79 | 80 | public void setDesc(String desc) { 81 | this.desc = desc; 82 | } 83 | 84 | public String getPublishedAt() { 85 | return publishedAt; 86 | } 87 | 88 | public void setPublishedAt(String publishedAt) { 89 | this.publishedAt = publishedAt; 90 | } 91 | 92 | public String getSource() { 93 | return source; 94 | } 95 | 96 | public void setSource(String source) { 97 | this.source = source; 98 | } 99 | 100 | public String getType() { 101 | return type; 102 | } 103 | 104 | public void setType(String type) { 105 | this.type = type; 106 | } 107 | 108 | public String getUrl() { 109 | return url; 110 | } 111 | 112 | public void setUrl(String url) { 113 | this.url = url; 114 | } 115 | 116 | public boolean isUsed() { 117 | return used; 118 | } 119 | 120 | public void setUsed(boolean used) { 121 | this.used = used; 122 | } 123 | 124 | public String getWho() { 125 | return who; 126 | } 127 | 128 | public void setWho(String who) { 129 | this.who = who; 130 | } 131 | 132 | public List getImages() { 133 | return images; 134 | } 135 | 136 | public void setImages(List images) { 137 | this.images = images; 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /app/src/main/java/ren/yale/android/retrofitcachetest/rx1/ApiRx1.java: -------------------------------------------------------------------------------- 1 | package ren.yale.android.retrofitcachetest.rx1; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import ren.yale.android.retrofitcachelib.anno.Cache; 6 | import ren.yale.android.retrofitcachelib.anno.Mock; 7 | import ren.yale.android.retrofitcachetest.bean.GankAndroid; 8 | import retrofit2.http.GET; 9 | import retrofit2.http.Query; 10 | import rx.Observable; 11 | 12 | /** 13 | * Created by Yale on 2017/6/13. 14 | */ 15 | 16 | public interface ApiRx1 { 17 | 18 | 19 | @Cache(time = 5,timeUnit = TimeUnit.SECONDS) 20 | @GET("Android/9/1") 21 | Observable getGankAndroid(@Query("aa") String aa); 22 | 23 | @Mock(value = "{\"error\":false,\"results\":[{\"_id\":\"5941f5f3421aa92c7be61c16\",\"createdAt\":\"2017-06-15T10:50:27.317Z\",\"desc\":\"22222222\\\\u4effNice\\\\u9996\\\\u9875\\\\u56fe\\\\u7247\\\\u5217\\\\u88689\\\\u56fe\\\\u6837\\\\u5f0f\\\\uff0c\\\\u5e76\\\\u5b9e\\\\u73b0\\\\u62d6\\\\u62fd\\\\u6548\\\\u679c\",\"images\":[\"http://img.gank.io/4f54c011-e293-436a-ada1-dc03669ffb10\"],\"publishedAt\":\"2017-06-15T13:55:57.947Z\",\"source\":\"web\",\"type\":\"Android\",\"url\":\"http://www.jianshu.com/p/0ea96b952170\",\"used\":true,\"who\":\"www的事发生飞洒地方bbb\"}]}") 24 | @GET("Android/10/4") 25 | Observable getRamMockGankAndroid(); 26 | 27 | @Mock(url = "http://gank.io/api/data/Android/10/2") 28 | @GET("Android/10/1") 29 | Observable getUrlMockGankAndroid(); 30 | 31 | @Mock(assets = "mock/mock.json") 32 | @GET("Android/10/5") 33 | Observable getAssetsMockGankAndroid(); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/ren/yale/android/retrofitcachetest/rx1/OKHttpUtilsRx1.java: -------------------------------------------------------------------------------- 1 | package ren.yale.android.retrofitcachetest.rx1; 2 | 3 | import android.content.Context; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import okhttp3.Cache; 10 | import okhttp3.Interceptor; 11 | import okhttp3.OkHttpClient; 12 | import okhttp3.Request; 13 | import okhttp3.Response; 14 | import ren.yale.android.retrofitcachelib.CacheInterceptorListener; 15 | import ren.yale.android.retrofitcachelib.RetrofitCache; 16 | import ren.yale.android.retrofitcachelib.intercept.CacheForceInterceptorNoNet; 17 | import ren.yale.android.retrofitcachelib.intercept.CacheInterceptorOnNet; 18 | import ren.yale.android.retrofitcachelib.transformer.CacheTransformer; 19 | import ren.yale.android.retrofitcachetest.LogTestUtil; 20 | import retrofit2.Retrofit; 21 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; 22 | import retrofit2.converter.gson.GsonConverterFactory; 23 | import rx.Observable; 24 | import rx.android.schedulers.AndroidSchedulers; 25 | import rx.functions.Func1; 26 | import rx.schedulers.Schedulers; 27 | 28 | /** 29 | * Created by Yale on 2017/6/12. 30 | */ 31 | public enum OKHttpUtilsRx1 { 32 | INSTANCE; 33 | private Context mContext; 34 | private static ApiRx1 apiRx1; 35 | public void init(Context context){ 36 | mContext = context; 37 | if (apiRx1 ==null){ 38 | apiRx1 = configRetrofit(ApiRx1.class,"http://gank.io/api/data/"); 39 | } 40 | RetrofitCache.getInstance().init(context); 41 | RetrofitCache.getInstance().setCacheInterceptorListener( 42 | new CacheInterceptorListener() { 43 | @Override 44 | public boolean canCache(Request request,Response response) { 45 | return true; 46 | } 47 | }); 48 | 49 | } 50 | 51 | public OkHttpClient getOkHttpClient(){ 52 | okhttp3.OkHttpClient.Builder clientBuilder=new okhttp3.OkHttpClient.Builder(); 53 | clientBuilder.readTimeout(20, TimeUnit.SECONDS); 54 | clientBuilder.connectTimeout(20, TimeUnit.SECONDS); 55 | clientBuilder.writeTimeout(20, TimeUnit.SECONDS); 56 | clientBuilder.addInterceptor(new LogInterceptor()); 57 | //clientBuilder.addInterceptor(new MockInterceptor()); 58 | clientBuilder.addInterceptor(new CacheForceInterceptorNoNet()); 59 | clientBuilder.addNetworkInterceptor(new CacheInterceptorOnNet()); 60 | clientBuilder.retryOnConnectionFailure(true); 61 | int cacheSize = 200 * 1024 * 1024; 62 | File cacheDirectory = new File(mContext.getCacheDir(), "httpcache"); 63 | Cache cache = new Cache(cacheDirectory, cacheSize); 64 | return clientBuilder.cache(cache).build(); 65 | } 66 | 67 | private static void showLog(String str) { 68 | str = str.trim(); 69 | int index = 0; 70 | int maxLength = 2000; 71 | String finalString=""; 72 | 73 | while (index < str.length()) { 74 | if (str.length() <= index + maxLength) { 75 | finalString = str.substring(index); 76 | } else { 77 | finalString = str.substring(index, index+maxLength); 78 | } 79 | index += maxLength; 80 | LogTestUtil.d( finalString.trim()); 81 | } 82 | } 83 | private class LogInterceptor implements Interceptor { 84 | 85 | 86 | public okhttp3.Response intercept(Chain chain) throws IOException { 87 | Request request = chain.request(); 88 | StringBuffer sb = new StringBuffer(); 89 | 90 | 91 | okhttp3.Response response = chain.proceed(chain.request()); 92 | okhttp3.MediaType mediaType = response.body().contentType(); 93 | String content = response.body().string(); 94 | 95 | LogTestUtil.d(response.headers().toString()); 96 | // sb.append("======== request: "+request.toString()+"\r\n ======== request headers: "+request.headers().toString()+"\r\n======= response header:"+response.headers().toString()+"\r\n---------- response body:\r\n"); 97 | LogTestUtil.d(sb.toString()); 98 | try { 99 | // showLog(content); 100 | }catch (Exception e){ 101 | e.printStackTrace(); 102 | } 103 | 104 | return response.newBuilder() 105 | .body(okhttp3.ResponseBody.create(mediaType, content)) 106 | .build(); 107 | } 108 | } 109 | public static Observable.Transformer IoMain() { 110 | 111 | return new Observable.Transformer() { 112 | @Override 113 | public Observable call(Observable tObservable) { 114 | 115 | return tObservable.compose(CacheTransformer.emptyTransformer()) 116 | .subscribeOn(Schedulers.io()) 117 | .observeOn(AndroidSchedulers.mainThread()).map(new Func1() { 118 | @Override 119 | public Object call(Object t) { 120 | 121 | return t; 122 | } 123 | }); 124 | } 125 | }; 126 | } 127 | 128 | 129 | public ApiRx1 getApi(){ 130 | return apiRx1; 131 | } 132 | 133 | 134 | private T configRetrofit(Class service,String url ) { 135 | Retrofit retrofit = new Retrofit.Builder() 136 | .baseUrl(url) 137 | .client(getOkHttpClient()) 138 | .addConverterFactory(GsonConverterFactory.create()) 139 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 140 | .build(); 141 | RetrofitCache.getInstance().addRetrofit(retrofit); 142 | return retrofit.create(service); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /app/src/main/java/ren/yale/android/retrofitcachetest/rx2/ApiRx2.java: -------------------------------------------------------------------------------- 1 | package ren.yale.android.retrofitcachetest.rx2; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import io.reactivex.Observable; 6 | import ren.yale.android.retrofitcachelib.anno.Cache; 7 | import ren.yale.android.retrofitcachelibrx2.anno.Mock; 8 | import ren.yale.android.retrofitcachetest.bean.GankAndroid; 9 | import retrofit2.http.GET; 10 | 11 | /** 12 | * Created by Yale on 2017/6/13. 13 | */ 14 | 15 | public interface ApiRx2 { 16 | 17 | @Mock(assets = "mock/mock.json") 18 | @Cache(time = 10,timeUnit = TimeUnit.SECONDS) 19 | @GET("Android/9/1") 20 | Observable getGankAndroid(); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/ren/yale/android/retrofitcachetest/rx2/OKHttpUtilsRx2.java: -------------------------------------------------------------------------------- 1 | package ren.yale.android.retrofitcachetest.rx2; 2 | 3 | import android.content.Context; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import io.reactivex.ObservableSource; 10 | import io.reactivex.ObservableTransformer; 11 | import io.reactivex.android.schedulers.AndroidSchedulers; 12 | import io.reactivex.schedulers.Schedulers; 13 | import okhttp3.Cache; 14 | import okhttp3.Interceptor; 15 | import okhttp3.OkHttpClient; 16 | import okhttp3.Request; 17 | import okhttp3.Response; 18 | import ren.yale.android.retrofitcachelibrx2.CacheInterceptorListener; 19 | import ren.yale.android.retrofitcachelibrx2.RetrofitCache; 20 | import ren.yale.android.retrofitcachelibrx2.intercept.CacheForceInterceptorNoNet; 21 | import ren.yale.android.retrofitcachelibrx2.intercept.CacheInterceptorOnNet; 22 | import ren.yale.android.retrofitcachelibrx2.transformer.CacheTransformer; 23 | import ren.yale.android.retrofitcachetest.LogTestUtil; 24 | import retrofit2.Retrofit; 25 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; 26 | import retrofit2.converter.gson.GsonConverterFactory; 27 | 28 | /** 29 | * Created by Yale on 2017/6/12. 30 | */ 31 | public enum OKHttpUtilsRx2 { 32 | INSTANCE; 33 | private Context mContext; 34 | private static ApiRx2 apiRx2; 35 | public void init(Context context){ 36 | mContext = context; 37 | if (apiRx2 ==null){ 38 | apiRx2 = configRetrofit(ApiRx2.class,"http://gank.io/api/data/"); 39 | } 40 | RetrofitCache.getInstance().init(context); 41 | RetrofitCache.getInstance().setCacheInterceptorListener( 42 | new CacheInterceptorListener() { 43 | @Override 44 | public boolean canCache(Request request,Response response) { 45 | return true; 46 | } 47 | }); 48 | 49 | } 50 | 51 | public OkHttpClient getOkHttpClient(){ 52 | OkHttpClient.Builder clientBuilder=new OkHttpClient.Builder(); 53 | clientBuilder.readTimeout(20, TimeUnit.SECONDS); 54 | clientBuilder.connectTimeout(20, TimeUnit.SECONDS); 55 | clientBuilder.writeTimeout(20, TimeUnit.SECONDS); 56 | clientBuilder.addInterceptor(new LogInterceptor()); 57 | //clientBuilder.addInterceptor(new MockInterceptor()); 58 | clientBuilder.addInterceptor(new CacheForceInterceptorNoNet()); 59 | clientBuilder.addNetworkInterceptor(new CacheInterceptorOnNet()); 60 | 61 | int cacheSize = 200 * 1024 * 1024; 62 | File cacheDirectory = new File(mContext.getCacheDir(), "httpcache"); 63 | Cache cache = new Cache(cacheDirectory, cacheSize); 64 | return clientBuilder.cache(cache).build(); 65 | } 66 | 67 | private static void showLog(String str) { 68 | str = str.trim(); 69 | int index = 0; 70 | int maxLength = 2000; 71 | String finalString=""; 72 | 73 | while (index < str.length()) { 74 | if (str.length() <= index + maxLength) { 75 | finalString = str.substring(index); 76 | } else { 77 | finalString = str.substring(index, index+maxLength); 78 | } 79 | index += maxLength; 80 | LogTestUtil.d( finalString.trim()); 81 | } 82 | } 83 | private class LogInterceptor implements Interceptor { 84 | 85 | 86 | public Response intercept(Chain chain) throws IOException { 87 | Request request = chain.request(); 88 | StringBuffer sb = new StringBuffer(); 89 | 90 | 91 | Response response = chain.proceed(chain.request()); 92 | okhttp3.MediaType mediaType = response.body().contentType(); 93 | String content = response.body().string(); 94 | 95 | 96 | sb.append("======== request: "+request.toString()+"\r\n ======== request headers: "+request.headers().toString()+"\r\n======= response header:"+response.headers().toString()+"\r\n---------- response body:\r\n"); 97 | LogTestUtil.d(sb.toString()); 98 | try { 99 | showLog(content); 100 | }catch (Exception e){ 101 | e.printStackTrace(); 102 | } 103 | 104 | return response.newBuilder() 105 | .body(okhttp3.ResponseBody.create(mediaType, content)) 106 | .build(); 107 | } 108 | } 109 | 110 | 111 | public ObservableTransformer IoMain() { 112 | return new ObservableTransformer() { 113 | @Override 114 | public ObservableSource apply(io.reactivex.Observable upstream) { 115 | return upstream.compose(CacheTransformer.emptyTransformer()). 116 | subscribeOn(Schedulers.io()) 117 | .observeOn(AndroidSchedulers.mainThread()); 118 | } 119 | }; 120 | } 121 | 122 | 123 | 124 | 125 | public ApiRx2 getApi(){ 126 | return apiRx2; 127 | } 128 | 129 | 130 | private T configRetrofit(Class service,String url ) { 131 | Retrofit retrofit = new Retrofit.Builder() 132 | .baseUrl(url) 133 | .client(getOkHttpClient()) 134 | .addConverterFactory(GsonConverterFactory.create()) 135 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 136 | .build(); 137 | RetrofitCache.getInstance().addRetrofit(retrofit); 138 | return retrofit.create(service); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 |