├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── findbugs-idea.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── lizubing │ │ └── smartcacheforretrofit2 │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── lizubing │ │ │ └── smartcacheforretrofit2 │ │ │ ├── ConfigConstants.java │ │ │ ├── FrescoHelper.java │ │ │ ├── ImageListAdapter.java │ │ │ ├── MainActivity.java │ │ │ ├── MyApplication.java │ │ │ ├── MyOkHttpImagePipelineConfigFactory.java │ │ │ ├── MyOkHttpNetworkFetcher.java │ │ │ ├── base │ │ │ └── MyBaseAdapter.java │ │ │ └── retrofit │ │ │ ├── ImageListBean.java │ │ │ ├── MainFactory.java │ │ │ └── MeoHttp.java │ └── res │ │ ├── layout │ │ ├── activity_main.xml │ │ └── item_imagelist.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── lizubing │ └── smartcacheforretrofit2 │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── smartcache ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src ├── androidTest └── java │ └── com │ └── lizubing │ └── smartcache │ └── ApplicationTest.java ├── main ├── AndroidManifest.xml ├── java │ └── com │ │ └── lizubing │ │ └── smartcache │ │ ├── AndroidExecutor.java │ │ ├── BasicCaching.java │ │ ├── CachingSystem.java │ │ ├── SmartCall.java │ │ ├── SmartCallFactory.java │ │ └── SmartUtils.java └── res │ └── values │ └── strings.xml └── test └── java └── com └── lizubing └── smartcache └── ExampleUnitTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/findbugs-idea.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 32 | 203 | 216 | 225 | 226 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 1.8 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Smartcacheforretrofit2 2 | 这个项目是修改SmartCache框架,增加了对retrofit2.0+以及okhttp3.0+的支持,并增加了demo演示 3 | 框架主要是用来增加缓存的,使用SmartCall作为的新的回调接口,可以做到先加载缓存后请求网络数据接口 4 | 个人认为对于okhttp自带的缓存不太好用,原框架使用的retrofit2.0beta版本,我使用的最新的2.1框架改写,发现 5 | 有很多api被修改或者移除,对于学习retrofit2.0+有一定的帮助 6 | 原项目框架:https://github.com/dimitrovskif/SmartCache 7 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.3" 6 | 7 | defaultConfig { 8 | applicationId "com.lizubing.smartcacheforretrofit2" 9 | minSdkVersion 15 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.facebook.fresco:fresco:0.9.0+' 26 | compile 'com.android.support:appcompat-v7:23.4.0' 27 | compile project(':smartcache') 28 | } 29 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/lizubing/smartcacheforretrofit2/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcacheforretrofit2; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/lizubing/smartcacheforretrofit2/ConfigConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file provided by Facebook is for non-commercial testing and evaluation 3 | * purposes only. Facebook reserves all rights not expressly granted. 4 | * 5 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 6 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 7 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 8 | * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 9 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 10 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | */ 12 | 13 | package com.lizubing.smartcacheforretrofit2; 14 | 15 | import android.content.Context; 16 | import android.content.res.Resources; 17 | import android.graphics.drawable.Drawable; 18 | import android.net.Uri; 19 | import android.os.Environment; 20 | 21 | import com.facebook.cache.disk.DiskCacheConfig; 22 | import com.facebook.common.internal.Supplier; 23 | import com.facebook.common.util.ByteConstants; 24 | import com.facebook.drawee.backends.pipeline.Fresco; 25 | import com.facebook.drawee.drawable.ProgressBarDrawable; 26 | import com.facebook.drawee.generic.GenericDraweeHierarchy; 27 | import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; 28 | import com.facebook.drawee.generic.RoundingParams; 29 | import com.facebook.drawee.interfaces.DraweeController; 30 | import com.facebook.drawee.interfaces.SimpleDraweeControllerBuilder; 31 | import com.facebook.drawee.view.SimpleDraweeView; 32 | import com.facebook.imagepipeline.cache.MemoryCacheParams; 33 | import com.facebook.imagepipeline.common.ImageDecodeOptions; 34 | import com.facebook.imagepipeline.common.ResizeOptions; 35 | import com.facebook.imagepipeline.core.ImagePipelineConfig; 36 | import com.facebook.imagepipeline.request.ImageRequest; 37 | import com.facebook.imagepipeline.request.ImageRequest.RequestLevel; 38 | import com.facebook.imagepipeline.request.ImageRequestBuilder; 39 | 40 | import okhttp3.OkHttpClient; 41 | 42 | /** 43 | * 配置才是关键~~~细细看来确实是不错的图片缓存框架, 44 | * 45 | */ 46 | public class ConfigConstants { 47 | private static final int MAX_HEAP_SIZE = (int) Runtime.getRuntime().maxMemory();//分配的可用内存 48 | public static final int MAX_MEMORY_CACHE_SIZE = MAX_HEAP_SIZE / 4;//使用的缓存数量 49 | 50 | public static final int MAX_SMALL_DISK_VERYLOW_CACHE_SIZE = 100 * ByteConstants.MB;//小图极低磁盘空间缓存的最大值(特性:可将大量的小图放到额外放在另一个磁盘空间防止大图占用磁盘空间而删除了大量的小图) 51 | public static final int MAX_SMALL_DISK_LOW_CACHE_SIZE = 100 * ByteConstants.MB;//小图低磁盘空间缓存的最大值(特性:可将大量的小图放到额外放在另一个磁盘空间防止大图占用磁盘空间而删除了大量的小图) 52 | public static final int MAX_SMALL_DISK_CACHE_SIZE = 200 * ByteConstants.MB;//小图磁盘缓存的最大值(特性:可将大量的小图放到额外放在另一个磁盘空间防止大图占用磁盘空间而删除了大量的小图) 53 | 54 | public static final int MAX_DISK_CACHE_VERYLOW_SIZE = 200 * ByteConstants.MB;//默认图极低磁盘空间缓存的最大值 55 | public static final int MAX_DISK_CACHE_LOW_SIZE = 500 * ByteConstants.MB;//默认图低磁盘空间缓存的最大值 56 | public static final int MAX_DISK_CACHE_SIZE = 1500 * ByteConstants.MB;//默认图磁盘缓存的最大值 57 | 58 | 59 | private static final String IMAGE_PIPELINE_SMALL_CACHE_DIR = "18touch_mengju/imagepipeline_cache";//小图所放路径的文件夹名 60 | private static final String IMAGE_PIPELINE_CACHE_DIR = "18touch_mengju/imagepipeline_cache";//默认图所放路径的文件夹名 61 | 62 | private static ImagePipelineConfig sImagePipelineConfig; 63 | 64 | private ConfigConstants(){ 65 | 66 | } 67 | /** 68 | * 初始化配置,单例 69 | */ 70 | public static ImagePipelineConfig getImagePipelineConfig(Context context) { 71 | if (sImagePipelineConfig == null) { 72 | // sImagePipelineConfig = configureCaches(context); 73 | sImagePipelineConfig = configureCaches(context); 74 | } 75 | 76 | return sImagePipelineConfig; 77 | } 78 | 79 | 80 | /** 81 | * 初始化配置 82 | */ 83 | private static ImagePipelineConfig configureCaches(Context context) { 84 | //内存配置 85 | final MemoryCacheParams bitmapCacheParams = new MemoryCacheParams( 86 | ConfigConstants.MAX_MEMORY_CACHE_SIZE, // 内存缓存中总图片的最大大小,以字节为单位。 87 | Integer.MAX_VALUE, // 内存缓存中图片的最大数量。 88 | ConfigConstants.MAX_MEMORY_CACHE_SIZE, // 内存缓存中准备清除但尚未被删除的总图片的最大大小,以字节为单位。 89 | Integer.MAX_VALUE, // 内存缓存中准备清除的总图片的最大数量。 90 | Integer.MAX_VALUE); // 内存缓存中单个图片的最大大小。 91 | 92 | //修改内存图片缓存数量,空间策略(这个方式有点恶心) 93 | Supplier mSupplierMemoryCacheParams= new Supplier() { 94 | @Override 95 | public MemoryCacheParams get() { 96 | return bitmapCacheParams; 97 | } 98 | }; 99 | 100 | //小图片的磁盘配置 101 | DiskCacheConfig diskSmallCacheConfig = DiskCacheConfig.newBuilder(MyApplication.getContext()) 102 | .setBaseDirectoryPath(context.getApplicationContext().getCacheDir())//缓存图片基路径 103 | .setBaseDirectoryName(IMAGE_PIPELINE_SMALL_CACHE_DIR)//文件夹名 104 | // .setCacheErrorLogger(cacheErrorLogger)//日志记录器用于日志错误的缓存。 105 | // .setCacheEventListener(cacheEventListener)//缓存事件侦听器。 106 | // .setDiskTrimmableRegistry(diskTrimmableRegistry)//类将包含一个注册表的缓存减少磁盘空间的环境。 107 | .setMaxCacheSize(ConfigConstants.MAX_DISK_CACHE_SIZE)//默认缓存的最大大小。 108 | .setMaxCacheSizeOnLowDiskSpace(MAX_SMALL_DISK_LOW_CACHE_SIZE)//缓存的最大大小,使用设备时低磁盘空间。 109 | .setMaxCacheSizeOnVeryLowDiskSpace(MAX_SMALL_DISK_VERYLOW_CACHE_SIZE)//缓存的最大大小,当设备极低磁盘空间 110 | // .setVersion(version) 111 | .build(); 112 | 113 | //默认图片的磁盘配置 114 | DiskCacheConfig diskCacheConfig = DiskCacheConfig.newBuilder(MyApplication.getContext()) 115 | .setBaseDirectoryPath(Environment.getExternalStorageDirectory().getAbsoluteFile())//缓存图片基路径 116 | .setBaseDirectoryName(IMAGE_PIPELINE_CACHE_DIR)//文件夹名 117 | // .setCacheErrorLogger(cacheErrorLogger)//日志记录器用于日志错误的缓存。 118 | // .setCacheEventListener(cacheEventListener)//缓存事件侦听器。 119 | // .setDiskTrimmableRegistry(diskTrimmableRegistry)//类将包含一个注册表的缓存减少磁盘空间的环境。 120 | .setMaxCacheSize(ConfigConstants.MAX_DISK_CACHE_SIZE)//默认缓存的最大大小。 121 | .setMaxCacheSizeOnLowDiskSpace(MAX_DISK_CACHE_LOW_SIZE)//缓存的最大大小,使用设备时低磁盘空间。 122 | .setMaxCacheSizeOnVeryLowDiskSpace(MAX_DISK_CACHE_VERYLOW_SIZE)//缓存的最大大小,当设备极低磁盘空间 123 | // .setVersion(version) 124 | .build(); 125 | 126 | //缓存图片配置 127 | ImagePipelineConfig.Builder configBuilder = ImagePipelineConfig.newBuilder(context) 128 | // .setAnimatedImageFactory(AnimatedImageFactory animatedImageFactory)//图片加载动画 129 | .setBitmapMemoryCacheParamsSupplier(mSupplierMemoryCacheParams)//内存缓存配置(一级缓存,已解码的图片) 130 | // .setCacheKeyFactory(cacheKeyFactory)//缓存Key工厂 131 | // .setEncodedMemoryCacheParamsSupplier(encodedCacheParamsSupplier)//内存缓存和未解码的内存缓存的配置(二级缓存) 132 | // .setExecutorSupplier(executorSupplier)//线程池配置 133 | // .setImageCacheStatsTracker(imageCacheStatsTracker)//统计缓存的命中率 134 | // .setImageDecoder(ImageDecoder imageDecoder) //图片解码器配置 135 | // .setIsPrefetchEnabledSupplier(Supplier isPrefetchEnabledSupplier)//图片预览(缩略图,预加载图等)预加载到文件缓存 136 | .setMainDiskCacheConfig(diskCacheConfig)//磁盘缓存配置(总,三级缓存) 137 | // .setMemoryTrimmableRegistry(memoryTrimmableRegistry) //内存用量的缩减,有时我们可能会想缩小内存用量。比如应用中有其他数据需要占用内存,不得不把图片缓存清除或者减小 或者我们想检查看看手机是否已经内存不够了。 138 | // .setNetworkFetchProducer(networkFetchProducer)//自定的网络层配置:如OkHttp,Volley 139 | // .setPoolFactory(poolFactory)//线程池工厂配置 140 | // .setProgressiveJpegConfig(progressiveJpegConfig)//渐进式JPEG图 141 | // .setRequestListeners(requestListeners)//图片请求监听 142 | // .setResizeAndRotateEnabledForNetwork(boolean resizeAndRotateEnabledForNetwork)//调整和旋转是否支持网络图片 143 | .setSmallImageDiskCacheConfig(diskSmallCacheConfig)//磁盘缓存配置(小图片,可选~三级缓存的小图优化缓存) 144 | ; 145 | // return configBuilder.build(); 146 | OkHttpClient okHttpClient = new OkHttpClient(); // build on your own 147 | ImagePipelineConfig config = MyOkHttpImagePipelineConfigFactory 148 | .newBuilder(context, okHttpClient) 149 | .setBitmapMemoryCacheParamsSupplier(mSupplierMemoryCacheParams) 150 | .setMainDiskCacheConfig(diskCacheConfig) 151 | .setSmallImageDiskCacheConfig(diskSmallCacheConfig) 152 | .build(); 153 | return config; 154 | } 155 | //圆形,圆角切图,对动图无效 156 | public static RoundingParams getRoundingParams(){ 157 | RoundingParams roundingParams = RoundingParams.fromCornersRadius(7f); 158 | // roundingParams.asCircle();//圆形 159 | // roundingParams.setBorder(color, width);//fresco:roundingBorderWidth="2dp"边框 fresco:roundingBorderColor="@color/border_color" 160 | // roundingParams.setCornersRadii(radii);//半径 161 | // roundingParams.setCornersRadii(topLeft, topRight, bottomRight, bottomLeft)//fresco:roundTopLeft="true" fresco:roundTopRight="false" fresco:roundBottomLeft="false" fresco:roundBottomRight="true" 162 | // roundingParams. setCornersRadius(radius);//fresco:roundedCornerRadius="1dp"圆角 163 | // roundingParams.setOverlayColor(overlayColor);//fresco:roundWithOverlayColor="@color/corner_color" 164 | // roundingParams.setRoundAsCircle(roundAsCircle);//圆 165 | // roundingParams.setRoundingMethod(roundingMethod); 166 | // fresco:progressBarAutoRotateInterval="1000"自动旋转间隔 167 | // 或用 fromCornersRadii 以及 asCircle 方法 168 | return roundingParams; 169 | } 170 | 171 | //Drawees DraweeHierarchy 组织 172 | public static GenericDraweeHierarchy getGenericDraweeHierarchy(Context context){ 173 | GenericDraweeHierarchy gdh = new GenericDraweeHierarchyBuilder(context.getResources()) 174 | // .reset()//重置 175 | // .setActualImageColorFilter(colorFilter)//颜色过滤 176 | // .setActualImageFocusPoint(focusPoint)//focusCrop, 需要指定一个居中点 177 | // .setActualImageMatrix(actualImageMatrix) 178 | // .setActualImageScaleType(actualImageScaleType)//fresco:actualImageScaleType="focusCrop"缩放类型 179 | // .setBackground(background)//fresco:backgroundImage="@color/blue"背景图片 180 | // .setBackgrounds(backgrounds) 181 | // .setFadeDuration(fadeDuration)//fresco:fadeDuration="300"加载图片动画时间 182 | .setFailureImage(ConfigConstants.sErrorDrawable)//fresco:failureImage="@drawable/error"失败图 183 | // .setFailureImage(failureDrawable, failureImageScaleType)//fresco:failureImageScaleType="centerInside"失败图缩放类型 184 | // .setOverlay(overlay)//fresco:overlayImage="@drawable/watermark"叠加图 185 | // .setOverlays(overlays) 186 | .setPlaceholderImage(ConfigConstants.sPlaceholderDrawable)//fresco:placeholderImage="@color/wait_color"占位图 187 | // .setPlaceholderImage(placeholderDrawable, placeholderImageScaleType)//fresco:placeholderImageScaleType="fitCenter"占位图缩放类型 188 | // .setPressedStateOverlay(drawable)//fresco:pressedStateOverlayImage="@color/red"按压状态下的叠加图 189 | .setProgressBarImage(new ProgressBarDrawable())//进度条fresco:progressBarImage="@drawable/progress_bar"进度条 190 | // .setProgressBarImage(progressBarImage, progressBarImageScaleType)//fresco:progressBarImageScaleType="centerInside"进度条类型 191 | // .setRetryImage(retryDrawable)//fresco:retryImage="@drawable/retrying"点击重新加载 192 | // .setRetryImage(retryDrawable, retryImageScaleType)//fresco:retryImageScaleType="centerCrop"点击重新加载缩放类型 193 | .setRoundingParams(RoundingParams.asCircle())//圆形/圆角fresco:roundAsCircle="true"圆形 194 | .build(); 195 | return gdh; 196 | } 197 | 198 | 199 | //DraweeView~~~SimpleDraweeView——UI组件 200 | // public static SimpleDraweeView getSimpleDraweeView(Context context,Uri uri){ 201 | // SimpleDraweeView simpleDraweeView=new SimpleDraweeView(context); 202 | // simpleDraweeView.setImageURI(uri); 203 | // simpleDraweeView.setAspectRatio(1.33f);//宽高缩放比 204 | // return simpleDraweeView; 205 | // } 206 | 207 | //SimpleDraweeControllerBuilder 208 | public static SimpleDraweeControllerBuilder getSimpleDraweeControllerBuilder(SimpleDraweeControllerBuilder sdcb,Uri uri, Object callerContext,DraweeController draweeController){ 209 | SimpleDraweeControllerBuilder controllerBuilder = sdcb 210 | .setUri(uri) 211 | .setCallerContext(callerContext) 212 | // .setAspectRatio(1.33f);//宽高缩放比 213 | .setOldController(draweeController); 214 | return controllerBuilder; 215 | } 216 | 217 | //图片解码 218 | public static ImageDecodeOptions getImageDecodeOptions(){ 219 | ImageDecodeOptions decodeOptions = ImageDecodeOptions.newBuilder() 220 | // .setBackgroundColor(Color.TRANSPARENT)//图片的背景颜色 221 | // .setDecodeAllFrames(decodeAllFrames)//解码所有帧 222 | // .setDecodePreviewFrame(decodePreviewFrame)//解码预览框 223 | // .setForceOldAnimationCode(forceOldAnimationCode)//使用以前动画 224 | // .setFrom(options)//使用已经存在的图像解码 225 | // .setMinDecodeIntervalMs(intervalMs)//最小解码间隔(分位单位) 226 | .setUseLastFrameForPreview(true)//使用最后一帧进行预览 227 | .build(); 228 | return decodeOptions; 229 | } 230 | 231 | //图片显示 232 | public static ImageRequest getImageRequest(SimpleDraweeView view,String uri){ 233 | ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(uri)) 234 | // .setAutoRotateEnabled(true)//自动旋转图片方向 235 | // .setImageDecodeOptions(getImageDecodeOptions())// 图片解码库 236 | // .setImageType(ImageType.SMALL)//图片类型,设置后可调整图片放入小图磁盘空间还是默认图片磁盘空间 237 | // .setLocalThumbnailPreviewsEnabled(true)//缩略图预览,影响图片显示速度(轻微) 238 | .setLowestPermittedRequestLevel(RequestLevel.FULL_FETCH)//请求经过缓存级别 BITMAP_MEMORY_CACHE,ENCODED_MEMORY_CACHE,DISK_CACHE,FULL_FETCH 239 | // .setPostprocessor(postprocessor)//修改图片 240 | // .setProgressiveRenderingEnabled(true)//渐进加载,主要用于渐进式的JPEG图,影响图片显示速度(普通) 241 | .setResizeOptions(new ResizeOptions(view.getLayoutParams().width, view.getLayoutParams().height))//调整大小 242 | // .setSource(Uri uri)//设置图片地址 243 | .build(); 244 | return imageRequest; 245 | } 246 | 247 | //DraweeController 控制 DraweeControllerBuilder 248 | public static DraweeController getDraweeController(ImageRequest imageRequest,SimpleDraweeView view){ 249 | DraweeController draweeController = Fresco.newDraweeControllerBuilder() 250 | // .reset()//重置 251 | .setAutoPlayAnimations(true)//自动播放图片动画 252 | // .setCallerContext(callerContext)//回调 253 | // .setControllerListener(view.getListener())//监听图片下载完毕等 254 | // .setDataSourceSupplier(dataSourceSupplier)//数据源 255 | // .setFirstAvailableImageRequests(firstAvailableImageRequests)//本地图片复用,可加入ImageRequest数组 256 | .setImageRequest(imageRequest)//设置单个图片请求~~~不可与setFirstAvailableImageRequests共用,配合setLowResImageRequest为高分辨率的图 257 | // .setLowResImageRequest(ImageRequest.fromUri(lowResUri))//先下载显示低分辨率的图 258 | .setOldController(view.getController())//DraweeController复用 259 | .setTapToRetryEnabled(true)//点击重新加载图 260 | .build(); 261 | return draweeController; 262 | } 263 | 264 | //默认加载图片和失败图片 265 | public static Drawable sPlaceholderDrawable; 266 | public static Drawable sErrorDrawable; 267 | 268 | @SuppressWarnings("deprecation") 269 | public static void init(final Resources resources) { 270 | if (sPlaceholderDrawable == null) { 271 | sPlaceholderDrawable = resources.getDrawable(R.mipmap.ic_launcher); 272 | } 273 | if (sErrorDrawable == null) { 274 | sErrorDrawable = resources.getDrawable(R.mipmap.ic_launcher); 275 | } 276 | } 277 | 278 | 279 | 280 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lizubing/smartcacheforretrofit2/FrescoHelper.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcacheforretrofit2; 2 | 3 | import android.content.res.Resources; 4 | import android.graphics.drawable.Drawable; 5 | import android.net.Uri; 6 | import android.text.TextUtils; 7 | 8 | import com.facebook.drawee.backends.pipeline.Fresco; 9 | import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder; 10 | import com.facebook.drawee.controller.ControllerListener; 11 | import com.facebook.drawee.generic.GenericDraweeHierarchy; 12 | import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; 13 | import com.facebook.drawee.generic.RoundingParams; 14 | import com.facebook.drawee.interfaces.DraweeController; 15 | import com.facebook.drawee.view.SimpleDraweeView; 16 | import com.facebook.imagepipeline.image.ImageInfo; 17 | 18 | public class FrescoHelper { 19 | //默认加载图片和失败图片 20 | public static Drawable sPlaceholderDrawable; 21 | public static Drawable sErrorDrawable; 22 | /** 23 | * 图像选项类 24 | * @param isRound 是否圆角 25 | * @param radius 圆角角度 26 | * @return 27 | */ 28 | public static GenericDraweeHierarchy getImageViewHierarchy(Resources resources, boolean isRound, float radius) { 29 | GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(resources); 30 | builder.setFailureImage(resources.getDrawable(R.mipmap.ic_launcher)); 31 | builder.setPlaceholderImage(resources.getDrawable(R.mipmap.ic_launcher)); 32 | builder.setFadeDuration(300); 33 | if (isRound) { 34 | RoundingParams roundingParams = RoundingParams.fromCornersRadius(radius); 35 | builder.setRoundingParams(roundingParams); 36 | } 37 | return builder.build(); 38 | } 39 | /** 40 | * 图像选项类 41 | * @param resources Resources 42 | * @param isRound 是否圆角 43 | * @param radius 圆角角度 44 | */ 45 | public static GenericDraweeHierarchy getImageProgHierarchy(Resources resources, boolean isRound, float radius) { 46 | GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(resources); 47 | builder.setFailureImage(resources.getDrawable(R.mipmap.ic_launcher)); 48 | builder.setPlaceholderImage(resources.getDrawable(R.mipmap.ic_launcher)); 49 | // builder.setProgressBarImage(new CustomProgressbarDrawable()); 50 | builder.setFadeDuration(300); 51 | if (isRound) { 52 | RoundingParams roundingParams = RoundingParams.fromCornersRadius(radius); 53 | builder.setRoundingParams(roundingParams); 54 | } 55 | return builder.build(); 56 | } 57 | 58 | /** 59 | * 图像选项类 60 | * @param uri 图片路径 61 | * @param oldController DraweeView.getoldcontroller 62 | * @param controllerListener 监听 63 | * @return 64 | */ 65 | public static DraweeController getImageViewController(String uri, DraweeController oldController, 66 | ControllerListener controllerListener) { 67 | PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder(); 68 | if (!TextUtils.isEmpty(uri)) { 69 | // Logger.d("StringUtils.utf8Encode(uri)"+StringUtils.utf8Encode(uri)); 70 | builder.setUri(Uri.parse(uri)); 71 | } 72 | if (oldController != null) { 73 | builder.setOldController(oldController); 74 | } 75 | if (controllerListener != null) { 76 | builder.setControllerListener(controllerListener); 77 | } 78 | return builder.build(); 79 | } 80 | 81 | /** 82 | * 加载图片 83 | * @param draweeView SimpleDraweeView 84 | * @param uri 地址url 85 | * @param isRound 是否是圆角 86 | * @param radius 圆角的角弧度 87 | */ 88 | public static void displayImageview(SimpleDraweeView draweeView, String uri,boolean isRound, float radius) { 89 | draweeView.setHierarchy(getImageViewHierarchy(MyApplication.getInstance().getResources(), isRound, radius)); 90 | draweeView.setController(getImageViewController(uri, draweeView.getController(), null)); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/com/lizubing/smartcacheforretrofit2/ImageListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcacheforretrofit2; 2 | 3 | import android.content.Intent; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import com.facebook.drawee.view.SimpleDraweeView; 10 | import com.lizubing.smartcacheforretrofit2.base.MyBaseAdapter; 11 | import com.lizubing.smartcacheforretrofit2.retrofit.ImageListBean; 12 | 13 | /** 14 | * Created by xing on 2016/7/19. 15 | */ 16 | public class ImageListAdapter extends MyBaseAdapter { 17 | @Override 18 | protected View getRealView(int position, View convertView, final ViewGroup parent) { 19 | ListViewItem item; 20 | if (null == convertView||null == convertView.getTag()) { 21 | convertView = LayoutInflater.from(parent.getContext()).inflate( 22 | R.layout.item_imagelist, null); 23 | item = new ListViewItem(convertView); 24 | convertView.setTag(item); 25 | }else{ 26 | item = (ListViewItem) convertView.getTag(); 27 | } 28 | final ImageListBean.TngouBean info = (ImageListBean.TngouBean) _data.get(position); 29 | item.home_title.setText(info.getTitle()); 30 | item.home_img.setAspectRatio(2.0f); 31 | FrescoHelper.displayImageview(item.home_img, "http://tnfs.tngou.net/image"+info.getImg(), false, 15); 32 | return convertView; 33 | } 34 | 35 | public class ListViewItem { 36 | public SimpleDraweeView home_img;// 图片 37 | public TextView home_title;// 标题 38 | public ListViewItem(View v) { 39 | home_img = (SimpleDraweeView) v.findViewById(R.id.img_icon); 40 | home_title = (TextView) v.findViewById(R.id.tv_title); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/lizubing/smartcacheforretrofit2/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcacheforretrofit2; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.widget.ListView; 6 | 7 | import com.lizubing.smartcacheforretrofit2.retrofit.ImageListBean; 8 | import com.lizubing.smartcacheforretrofit2.retrofit.MainFactory; 9 | 10 | import retrofit2.Call; 11 | import retrofit2.Callback; 12 | import retrofit2.Response; 13 | 14 | public class MainActivity extends AppCompatActivity { 15 | 16 | private ListView listView; 17 | private ImageListAdapter adapter; 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_main); 23 | initView(); 24 | initData(); 25 | } 26 | 27 | private void initData() { 28 | MainFactory.getInstance().getImageList().enqueue(new Callback() { 29 | @Override 30 | public void onResponse(Call call, Response response) { 31 | adapter.setData(response.body().getTngou()); 32 | } 33 | 34 | @Override 35 | public void onFailure(Call call, Throwable t) { 36 | 37 | } 38 | }); 39 | } 40 | 41 | private void initView() { 42 | listView = (ListView) findViewById(R.id.list); 43 | adapter = new ImageListAdapter(); 44 | listView.setAdapter(adapter); 45 | } 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/lizubing/smartcacheforretrofit2/MyApplication.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcacheforretrofit2; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | import com.facebook.drawee.backends.pipeline.Fresco; 7 | 8 | /** 9 | * Created by xing on 2016/7/19. 10 | */ 11 | public class MyApplication extends Application{ 12 | 13 | private static MyApplication appcontext = null; 14 | public void onCreate() { 15 | super.onCreate(); 16 | appcontext = this; 17 | Fresco.initialize(appcontext, ConfigConstants.getImagePipelineConfig(appcontext)); 18 | } 19 | 20 | // 单例模式 21 | public static MyApplication getInstance() { 22 | return appcontext; 23 | } 24 | public static Context getContext() { 25 | return appcontext; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/lizubing/smartcacheforretrofit2/MyOkHttpImagePipelineConfigFactory.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcacheforretrofit2; 2 | 3 | import android.content.Context; 4 | 5 | import com.facebook.imagepipeline.core.ImagePipelineConfig; 6 | 7 | import okhttp3.OkHttpClient; 8 | 9 | /** 10 | * Created by admin on 2016/1/8. 11 | *

12 | * This source code is licensed under the BSD-style license found in the 13 | * LICENSE file in the root directory of this source tree. An additional grant 14 | * of patent rights can be found in the PATENTS file in the same directory. 15 | */ 16 | public class MyOkHttpImagePipelineConfigFactory { 17 | 18 | public static ImagePipelineConfig.Builder newBuilder(Context context, OkHttpClient okHttpClient) { 19 | return ImagePipelineConfig.newBuilder(context).setNetworkFetcher(new MyOkHttpNetworkFetcher(okHttpClient)); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/lizubing/smartcacheforretrofit2/MyOkHttpNetworkFetcher.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcacheforretrofit2; 2 | 3 | import android.net.Uri; 4 | import android.os.Looper; 5 | import android.os.SystemClock; 6 | import android.util.Log; 7 | 8 | import com.facebook.imagepipeline.image.EncodedImage; 9 | import com.facebook.imagepipeline.producers.BaseNetworkFetcher; 10 | import com.facebook.imagepipeline.producers.BaseProducerContextCallbacks; 11 | import com.facebook.imagepipeline.producers.Consumer; 12 | import com.facebook.imagepipeline.producers.FetchState; 13 | import com.facebook.imagepipeline.producers.ProducerContext; 14 | 15 | import java.io.IOException; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | import java.util.concurrent.Executor; 19 | 20 | import okhttp3.CacheControl; 21 | import okhttp3.Call; 22 | import okhttp3.OkHttpClient; 23 | import okhttp3.Request; 24 | import okhttp3.Response; 25 | import okhttp3.ResponseBody; 26 | 27 | /** 28 | * This source code is licensed under the BSD-style license found in the 29 | * LICENSE file in the root directory of this source tree. An additional grant 30 | * of patent rights can be found in the PATENTS file in the same directory. 31 | *

32 | * Created by admin on 2016/1/8. 33 | *

34 | * Network fetcher that uses OkHttp as a backend. 35 | */ 36 | public class MyOkHttpNetworkFetcher extends BaseNetworkFetcher { 37 | 38 | public static class MyOkHttpNetworkFetchState extends FetchState { 39 | 40 | public long submitTime; 41 | public long responseTime; 42 | public long fetchCompleteTime; 43 | 44 | public MyOkHttpNetworkFetchState(Consumer consumer, ProducerContext context) { 45 | super(consumer, context); 46 | } 47 | 48 | } 49 | 50 | private static final String TAG = "MyOkHttpNetworkFetcher"; 51 | 52 | private static final String QUEUE_TIME = "queue_time"; 53 | private static final String FETCH_TIME = "fetch_time"; 54 | private static final String TOTAL_TIME = "total_time"; 55 | private static final String IMAGE_SIZE = "image_size"; 56 | 57 | private final OkHttpClient mOkHttpClient; 58 | 59 | private Executor mCancellationExecutor; 60 | 61 | public MyOkHttpNetworkFetcher(OkHttpClient okHttpClient) { 62 | mOkHttpClient = okHttpClient; 63 | mCancellationExecutor = okHttpClient.dispatcher().executorService(); 64 | } 65 | 66 | @Override 67 | public MyOkHttpNetworkFetchState createFetchState(Consumer consumer, ProducerContext producerContext) { 68 | return new MyOkHttpNetworkFetchState(consumer, producerContext); 69 | } 70 | 71 | @Override 72 | public void fetch(final MyOkHttpNetworkFetchState fetchState, final Callback callback) { 73 | fetchState.submitTime = SystemClock.elapsedRealtime(); 74 | 75 | final Uri uri = fetchState.getUri(); 76 | 77 | final Request request = new Request.Builder() 78 | .cacheControl(new CacheControl.Builder().noStore().build()) 79 | .url(uri.toString()) 80 | .get() 81 | .build(); 82 | 83 | final Call call = mOkHttpClient.newCall(request); 84 | 85 | fetchState.getContext().addCallbacks(new BaseProducerContextCallbacks() { 86 | @Override 87 | public void onCancellationRequested() { 88 | if (Looper.myLooper() != Looper.getMainLooper()) { 89 | call.cancel(); 90 | } else { 91 | mCancellationExecutor.execute(new Runnable() { 92 | @Override 93 | public void run() { 94 | call.cancel(); 95 | } 96 | }); 97 | } 98 | } 99 | }); 100 | 101 | call.enqueue(new okhttp3.Callback() { 102 | @Override 103 | public void onFailure(Call call, IOException e) { 104 | handleException(call, e, callback); 105 | } 106 | 107 | @Override 108 | public void onResponse(Call call, Response response) throws IOException { 109 | fetchState.responseTime = SystemClock.elapsedRealtime(); 110 | final ResponseBody body = response.body(); 111 | try { 112 | long contentLength = body.contentLength(); 113 | if (contentLength < 0) { 114 | contentLength = 0; 115 | } 116 | callback.onResponse(body.byteStream(), (int) contentLength); 117 | } catch (Exception e) { 118 | handleException(call, e, callback); 119 | } finally { 120 | try { 121 | body.close(); 122 | } catch (Exception e) { 123 | Log.w(TAG, "Exception when closing response body", e); 124 | } 125 | } 126 | } 127 | }); 128 | 129 | } 130 | 131 | @Override 132 | public void onFetchCompletion(MyOkHttpNetworkFetchState fetchState, int byteSize) { 133 | fetchState.fetchCompleteTime = SystemClock.elapsedRealtime(); 134 | } 135 | 136 | @Override 137 | public Map getExtraMap(MyOkHttpNetworkFetchState fetchState, int byteSize) { 138 | Map extraMap = new HashMap<>(4); 139 | extraMap.put(QUEUE_TIME, Long.toString(fetchState.responseTime - fetchState.submitTime)); 140 | extraMap.put(FETCH_TIME, Long.toString(fetchState.fetchCompleteTime - fetchState.responseTime)); 141 | extraMap.put(TOTAL_TIME, Long.toString(fetchState.fetchCompleteTime - fetchState.submitTime)); 142 | extraMap.put(IMAGE_SIZE, Integer.toString(byteSize)); 143 | return extraMap; 144 | } 145 | 146 | /** 147 | * Handles exceptions. 148 | *

149 | *

OkHttp notifies callers of cancellations via an IOException. If IOException is caught 150 | * after request cancellation, then the exception is interpreted as successful cancellation 151 | * and onCancellation is called. Otherwise onFailure is called. 152 | */ 153 | private void handleException(final Call call, final Exception e, final Callback callback) { 154 | if (call.isCanceled()) { 155 | callback.onCancellation(); 156 | } else { 157 | callback.onFailure(e); 158 | } 159 | } 160 | 161 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lizubing/smartcacheforretrofit2/base/MyBaseAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcacheforretrofit2.base; 2 | 3 | import android.view.View; 4 | import android.view.ViewGroup; 5 | import android.widget.BaseAdapter; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * 设置不同个状态显示数据 12 | * @author Win7 13 | * 14 | */ 15 | public class MyBaseAdapter extends BaseAdapter { 16 | @SuppressWarnings("rawtypes") 17 | protected ArrayList _data = new ArrayList(); 18 | 19 | @Override 20 | public int getCount() { 21 | return getDataSize(); 22 | } 23 | /** 24 | * data数据的大小 25 | * @return 26 | */ 27 | public int getDataSize() { 28 | return _data.size(); 29 | } 30 | 31 | @Override 32 | public Object getItem(int arg0) { 33 | if (_data.size() > arg0) { 34 | return _data.get(arg0); 35 | } 36 | return null; 37 | } 38 | 39 | @Override 40 | public long getItemId(int arg0) { 41 | return arg0; 42 | } 43 | 44 | @SuppressWarnings("rawtypes") 45 | public void setData(ArrayList data) { 46 | _data = data; 47 | notifyDataSetChanged(); 48 | } 49 | 50 | @SuppressWarnings("rawtypes") 51 | public ArrayList getData() { 52 | return _data == null ? (_data = new ArrayList()) : _data; 53 | } 54 | 55 | @SuppressWarnings({ "unchecked", "rawtypes" }) 56 | public void addData(List data) { 57 | if (_data == null) { 58 | _data = new ArrayList(); 59 | } 60 | _data.addAll(data); 61 | notifyDataSetChanged(); 62 | } 63 | 64 | @SuppressWarnings({ "unchecked", "rawtypes" }) 65 | public void addItem(Object obj) { 66 | if (_data == null) { 67 | _data = new ArrayList(); 68 | } 69 | _data.add(obj); 70 | notifyDataSetChanged(); 71 | } 72 | 73 | @SuppressWarnings({ "rawtypes", "unchecked" }) 74 | public void addItem(int pos, Object obj) { 75 | if (_data == null) { 76 | _data = new ArrayList(); 77 | } 78 | _data.add(pos, obj); 79 | notifyDataSetChanged(); 80 | } 81 | 82 | public void removeItem(Object obj) { 83 | _data.remove(obj); 84 | notifyDataSetChanged(); 85 | } 86 | public void removeByPosition(int i) { 87 | _data.remove(i); 88 | notifyDataSetChanged(); 89 | } 90 | 91 | 92 | public void clear() { 93 | _data.clear(); 94 | notifyDataSetChanged(); 95 | } 96 | 97 | @Override 98 | public View getView(int position, View convertView, ViewGroup parent) { 99 | 100 | return getRealView(position, convertView, parent); 101 | } 102 | 103 | protected View getRealView(int position, View convertView, ViewGroup parent) { 104 | return null; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/java/com/lizubing/smartcacheforretrofit2/retrofit/ImageListBean.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcacheforretrofit2.retrofit; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by xing on 2016/7/19. 8 | */ 9 | public class ImageListBean { 10 | 11 | 12 | /** 13 | * status : true 14 | * total : 752 15 | * tngou : [{"count":292,"fcount":0,"galleryclass":4,"id":766,"img":"/ext/160717/0cac4d91e152e76d9e50f700a1025fca.jpg","rcount":0,"size":6,"time":1468728796000,"title":"妩媚的裸身性感美女一丝不挂销魂床上私房照"},{"count":230,"fcount":0,"galleryclass":1,"id":765,"img":"/ext/160717/29f188fadcd57812ed305df6e4ce3a65.jpg","rcount":0,"size":8,"time":1468728652000,"title":"90后酥胸正妹可爱自拍"},{"count":186,"fcount":0,"galleryclass":4,"id":764,"img":"/ext/160717/72ce009cd73a23e30dc9c8b0cc294d76.jpg","rcount":0,"size":21,"time":1468728613000,"title":"美女幼师Evelyn艾莉浴室勇斗私房照"},{"count":312,"fcount":0,"galleryclass":7,"id":763,"img":"/ext/160714/2507ee143d6285680b9ee1a2501c3308.jpg","rcount":0,"size":9,"time":1468497460000,"title":"性感车模与奔驰激情碰撞魅力无限"},{"count":176,"fcount":0,"galleryclass":7,"id":762,"img":"/ext/160714/b36610cc6d080e569a541102de5bb2f7.jpg","rcount":0,"size":9,"time":1468497405000,"title":"蓝色妖姬车展包裙尽显魅力高清大图"},{"count":234,"fcount":0,"galleryclass":5,"id":761,"img":"/ext/160714/41a62b88753dbb148a7d065474d89191.jpg","rcount":0,"size":10,"time":1468497350000,"title":"性感嫩模潘恩思性感包裙艺术"},{"count":139,"fcount":0,"galleryclass":5,"id":760,"img":"/ext/160714/43731ba40326757b80956306573cf0d0.jpg","rcount":0,"size":6,"time":1468497264000,"title":"性感女星刘凡菲笑容明媚宛若气质公主"},{"count":103,"fcount":0,"galleryclass":5,"id":759,"img":"/ext/160714/4eabc89d447fcc1f1f62393b9760978d.jpg","rcount":0,"size":6,"time":1468497149000,"title":"百变女王张虹紧身群性感时尚写"},{"count":80,"fcount":0,"galleryclass":5,"id":758,"img":"/ext/160714/c01d95059203c6b4186b78e5794d0a40.jpg","rcount":0,"size":5,"time":1468497087000,"title":"性感美女郝泽嘉酥胸隐现魅力"},{"count":351,"fcount":0,"galleryclass":3,"id":757,"img":"/ext/160713/a2cc1eea970661a2447a2ec6a4330501.jpg","rcount":0,"size":4,"time":1468415744000,"title":"Beautyleg美女超短旗袍私房照"},{"count":118,"fcount":0,"galleryclass":5,"id":756,"img":"/ext/160713/56061edae6c4556b5dace5e3c66c8a22.jpg","rcount":0,"size":3,"time":1468415682000,"title":"气质白衣制服诱惑美女"},{"count":555,"fcount":0,"galleryclass":6,"id":755,"img":"/ext/160713/57b0437520f390f2c36914e8290cae6b.jpg","rcount":0,"size":6,"time":1468415630000,"title":"极品日本巨乳美女 浑圆光滑的大奶少妇亚洲大尺度人体艺术图片"},{"count":487,"fcount":0,"galleryclass":1,"id":754,"img":"/ext/160713/daa8900536d4d82a0cd32f397b18e16c.jpg","rcount":0,"size":11,"time":1468415580000,"title":"带眼镜的麻辣白领美女办公室职业装黑丝美腿写真"},{"count":216,"fcount":0,"galleryclass":3,"id":753,"img":"/ext/160713/676453bc8b3c1a2b32cc6e04d376bbda.jpg","rcount":0,"size":17,"time":1468415535000,"title":"简晓育vicni蓝色紧身短裙制服黑丝美腿写真"},{"count":96,"fcount":0,"galleryclass":7,"id":752,"img":"/ext/160713/0d5e649ce564dbf35a9e78c5bd6f28fc.jpg","rcount":0,"size":4,"time":1468415465000,"title":"白皙巨乳车模美女车展电眼迷人气质美胸唯美大胆写真图片"},{"count":253,"fcount":0,"galleryclass":7,"id":751,"img":"/ext/160711/455754b5e4dd37fa918ed6dfe7801077.jpg","rcount":0,"size":4,"time":1468237275000,"title":"韩国美女白衣秀大长腿性感写真"},{"count":261,"fcount":0,"galleryclass":3,"id":750,"img":"/ext/160711/bc5ede5c4f2f3a3775ba05cb829d5a29.jpg","rcount":0,"size":7,"time":1468237211000,"title":"韩雪彩色丝袜完美身段性感时尚"},{"count":644,"fcount":0,"galleryclass":1,"id":749,"img":"/ext/160711/8d0093442185844e6250a32cd7b1691d.jpg","rcount":0,"size":9,"time":1468237172000,"title":"翘臀美女开叉礼服装大胆私房"},{"count":199,"fcount":0,"galleryclass":4,"id":748,"img":"/ext/160711/41b79f4d0848d2c0ede366e3cb6c8718.jpg","rcount":0,"size":9,"time":1468237113000,"title":"极品嫩模深V爆乳性感美腿写真"},{"count":109,"fcount":0,"galleryclass":5,"id":747,"img":"/ext/160711/b5308c4afc253ab8df4c04b3e7b38538.jpg","rcount":0,"size":8,"time":1468237071000,"title":"气质美女包臀短裙性感美腿写真图片"}] 16 | */ 17 | 18 | private boolean status; 19 | private int total; 20 | /** 21 | * count : 292 22 | * fcount : 0 23 | * galleryclass : 4 24 | * id : 766 25 | * img : /ext/160717/0cac4d91e152e76d9e50f700a1025fca.jpg 26 | * rcount : 0 27 | * size : 6 28 | * time : 1468728796000 29 | * title : 妩媚的裸身性感美女一丝不挂销魂床上私房照 30 | */ 31 | 32 | private ArrayList tngou; 33 | 34 | public boolean isStatus() { 35 | return status; 36 | } 37 | 38 | public void setStatus(boolean status) { 39 | this.status = status; 40 | } 41 | 42 | public int getTotal() { 43 | return total; 44 | } 45 | 46 | public void setTotal(int total) { 47 | this.total = total; 48 | } 49 | 50 | public ArrayList getTngou() { 51 | return tngou; 52 | } 53 | 54 | public void setTngou(ArrayList tngou) { 55 | this.tngou = tngou; 56 | } 57 | 58 | public static class TngouBean { 59 | private int count; 60 | private int fcount; 61 | private int galleryclass; 62 | private int id; 63 | private String img; 64 | private int rcount; 65 | private int size; 66 | private long time; 67 | private String title; 68 | 69 | public int getCount() { 70 | return count; 71 | } 72 | 73 | public void setCount(int count) { 74 | this.count = count; 75 | } 76 | 77 | public int getFcount() { 78 | return fcount; 79 | } 80 | 81 | public void setFcount(int fcount) { 82 | this.fcount = fcount; 83 | } 84 | 85 | public int getGalleryclass() { 86 | return galleryclass; 87 | } 88 | 89 | public void setGalleryclass(int galleryclass) { 90 | this.galleryclass = galleryclass; 91 | } 92 | 93 | public int getId() { 94 | return id; 95 | } 96 | 97 | public void setId(int id) { 98 | this.id = id; 99 | } 100 | 101 | public String getImg() { 102 | return img; 103 | } 104 | 105 | public void setImg(String img) { 106 | this.img = img; 107 | } 108 | 109 | public int getRcount() { 110 | return rcount; 111 | } 112 | 113 | public void setRcount(int rcount) { 114 | this.rcount = rcount; 115 | } 116 | 117 | public int getSize() { 118 | return size; 119 | } 120 | 121 | public void setSize(int size) { 122 | this.size = size; 123 | } 124 | 125 | public long getTime() { 126 | return time; 127 | } 128 | 129 | public void setTime(long time) { 130 | this.time = time; 131 | } 132 | 133 | public String getTitle() { 134 | return title; 135 | } 136 | 137 | public void setTitle(String title) { 138 | this.title = title; 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /app/src/main/java/com/lizubing/smartcacheforretrofit2/retrofit/MainFactory.java: -------------------------------------------------------------------------------- 1 | 2 | package com.lizubing.smartcacheforretrofit2.retrofit; 3 | 4 | import com.google.gson.Gson; 5 | import com.google.gson.GsonBuilder; 6 | import com.lizubing.smartcache.BasicCaching; 7 | import com.lizubing.smartcache.SmartCallFactory; 8 | import com.lizubing.smartcacheforretrofit2.MyApplication; 9 | 10 | import java.io.IOException; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | import okhttp3.Interceptor; 14 | import okhttp3.OkHttpClient; 15 | import okhttp3.Request; 16 | import okhttp3.Response; 17 | import retrofit2.Retrofit; 18 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; 19 | import retrofit2.converter.gson.GsonConverterFactory; 20 | 21 | /** 22 | * 无缓存get post请求 23 | * 支持Rxjava Observable 24 | */ 25 | public class MainFactory { 26 | public static final String HOST = "http://www.tngou.net/"; 27 | 28 | private static MeoHttp mGuDong; 29 | 30 | protected static final Object monitor = new Object(); 31 | 32 | public static MeoHttp getInstance(){ 33 | synchronized (monitor){ 34 | if(mGuDong==null){ 35 | Gson gson = new GsonBuilder() 36 | .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") 37 | .create(); 38 | SmartCallFactory smartFactory = new SmartCallFactory(BasicCaching.fromCtx(MyApplication.getContext())); 39 | //实现拦截器,设置请求头 40 | Interceptor interceptorImpl = new Interceptor() { 41 | @Override 42 | public Response intercept(Chain chain) throws IOException { 43 | Request request = chain.request(); 44 | Request compressedRequest = request.newBuilder() 45 | .header("X-Requested-With", "XMLHttpRequest") 46 | .build(); 47 | return chain.proceed(compressedRequest); 48 | } 49 | }; 50 | //设置OKHttpClient 51 | OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder() 52 | .connectTimeout(2, TimeUnit.SECONDS) 53 | .writeTimeout(60, TimeUnit.SECONDS) 54 | .readTimeout(60, TimeUnit.SECONDS) 55 | .addInterceptor(interceptorImpl);//创建OKHttpClient的Builder 56 | //build OKHttpClient 57 | OkHttpClient okHttpClient = httpClientBuilder.build(); 58 | Retrofit client = new Retrofit.Builder() 59 | .baseUrl(HOST) 60 | .client(okHttpClient) 61 | .addConverterFactory(GsonConverterFactory.create(gson)) 62 | .addCallAdapterFactory(smartFactory) 63 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 64 | .build(); 65 | mGuDong = client.create(MeoHttp.class); 66 | } 67 | return mGuDong; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/com/lizubing/smartcacheforretrofit2/retrofit/MeoHttp.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcacheforretrofit2.retrofit; 2 | 3 | 4 | import com.lizubing.smartcache.SmartCall; 5 | 6 | import retrofit2.http.GET; 7 | 8 | public interface MeoHttp { 9 | 10 | /** 11 | * 获得图片列表 12 | */ 13 | @GET("tnfs/api/list") 14 | SmartCall getImageList(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_imagelist.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 11 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizubing1992/Smartcacheforretrofit2/fa6cde08c090ce367e89dc0748a8a17701aee969/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizubing1992/Smartcacheforretrofit2/fa6cde08c090ce367e89dc0748a8a17701aee969/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizubing1992/Smartcacheforretrofit2/fa6cde08c090ce367e89dc0748a8a17701aee969/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizubing1992/Smartcacheforretrofit2/fa6cde08c090ce367e89dc0748a8a17701aee969/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizubing1992/Smartcacheforretrofit2/fa6cde08c090ce367e89dc0748a8a17701aee969/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Smartcacheforretrofit2 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/lizubing/smartcacheforretrofit2/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcacheforretrofit2; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.5.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizubing1992/Smartcacheforretrofit2/fa6cde08c090ce367e89dc0748a8a17701aee969/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 21 11:34:03 PDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':smartcache' 2 | -------------------------------------------------------------------------------- /smartcache/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /smartcache/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.3" 6 | 7 | defaultConfig { 8 | minSdkVersion 15 9 | targetSdkVersion 23 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile fileTree(dir: 'libs', include: ['*.jar']) 23 | testCompile 'junit:junit:4.12' 24 | compile 'com.jakewharton:disklrucache:2.0.2' 25 | compile 'com.squareup.retrofit2:retrofit:2.1.0'//修改成2.0版本 26 | compile 'com.squareup.retrofit2:converter-gson:2.1.0' 27 | compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' 28 | compile 'com.android.support:appcompat-v7:23.4.0' 29 | compile 'com.google.guava:guava:18.0' 30 | } 31 | -------------------------------------------------------------------------------- /smartcache/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /smartcache/src/androidTest/java/com/lizubing/smartcache/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcache; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /smartcache/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /smartcache/src/main/java/com/lizubing/smartcache/AndroidExecutor.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcache; 2 | 3 | import android.os.Handler; 4 | import android.os.Looper; 5 | 6 | import java.util.concurrent.Executor; 7 | 8 | class AndroidExecutor implements Executor { 9 | private final Handler handler = new Handler(Looper.getMainLooper()); 10 | 11 | @Override 12 | public void execute(Runnable r) { 13 | handler.post(r); 14 | } 15 | } -------------------------------------------------------------------------------- /smartcache/src/main/java/com/lizubing/smartcache/BasicCaching.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcache; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | import android.util.LruCache; 6 | 7 | import com.google.common.hash.Hashing; 8 | import com.jakewharton.disklrucache.DiskLruCache; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | import java.net.URL; 13 | import java.nio.charset.Charset; 14 | 15 | import okhttp3.Request; 16 | import retrofit2.Response; 17 | 18 | 19 | /** 20 | * A basic caching system that stores responses in RAM & disk 21 | * It uses {@link DiskLruCache} and {@link LruCache} to do the former. 22 | */ 23 | public class BasicCaching implements CachingSystem { 24 | private DiskLruCache diskCache; 25 | private LruCache memoryCache; 26 | 27 | public BasicCaching(File diskDirectory, long maxDiskSize, int memoryEntries){ 28 | try{ 29 | diskCache = DiskLruCache.open(diskDirectory, 1, 1, maxDiskSize); 30 | }catch(IOException exc){ 31 | Log.e("SmartCall", "", exc); 32 | diskCache = null; 33 | } 34 | 35 | memoryCache = new LruCache<>(memoryEntries); 36 | } 37 | 38 | private static final long REASONABLE_DISK_SIZE = 1024 * 1024; // 1 MB 39 | private static final int REASONABLE_MEM_ENTRIES = 50; // 50 entries 40 | 41 | /*** 42 | * Constructs a BasicCaching system using settings that should work for everyone 43 | * @param context 44 | * @return 45 | */ 46 | public static BasicCaching fromCtx(Context context){ 47 | return new BasicCaching( 48 | new File(context.getCacheDir(), "retrofit_smartcache"), 49 | REASONABLE_DISK_SIZE, 50 | REASONABLE_MEM_ENTRIES); 51 | } 52 | 53 | @Override 54 | public void addInCache(Response response, byte[] rawResponse) { 55 | String cacheKey = urlToKey(response.raw().request().url().url()); 56 | memoryCache.put(cacheKey, rawResponse); 57 | 58 | try { 59 | DiskLruCache.Editor editor = diskCache.edit(urlToKey(response.raw().request().url().url())); 60 | editor.set(0, new String(rawResponse, Charset.defaultCharset())); 61 | editor.commit(); 62 | }catch(IOException exc){ 63 | Log.e("SmartCall", "", exc); 64 | } 65 | } 66 | 67 | @Override 68 | public byte[] getFromCache(Request request) { 69 | String cacheKey = urlToKey(request.url().url()); 70 | byte[] memoryResponse = (byte[]) memoryCache.get(cacheKey); 71 | if(memoryResponse != null){ 72 | Log.d("SmartCall", "Memory hit!"); 73 | return memoryResponse; 74 | } 75 | 76 | try { 77 | DiskLruCache.Snapshot cacheSnapshot = diskCache.get(cacheKey); 78 | if(cacheSnapshot != null){ 79 | Log.d("SmartCall", "Disk hit!"); 80 | return cacheSnapshot.getString(0).getBytes(); 81 | }else{ 82 | return null; 83 | } 84 | }catch(IOException exc){ 85 | return null; 86 | } 87 | } 88 | 89 | private String urlToKey(URL url){ 90 | return Hashing.sha1().hashString(url.toString(), Charset.defaultCharset()).toString(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /smartcache/src/main/java/com/lizubing/smartcache/CachingSystem.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcache; 2 | 3 | 4 | import okhttp3.Request; 5 | import retrofit2.Response; 6 | 7 | public interface CachingSystem { 8 | void addInCache(Response response, byte[] rawResponse); 9 | byte[] getFromCache(Request request); 10 | } 11 | -------------------------------------------------------------------------------- /smartcache/src/main/java/com/lizubing/smartcache/SmartCall.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcache; 2 | 3 | 4 | import java.io.IOException; 5 | import java.lang.reflect.Type; 6 | 7 | import okhttp3.Request; 8 | import retrofit2.Callback; 9 | import retrofit2.Response; 10 | 11 | 12 | public interface SmartCall{ 13 | /** 14 | * Asynchronously send the request and notify {@code callback} of its response or if an error 15 | * occurred talking to the server, creating the request, or processing the response. 16 | */ 17 | void enqueue(Callback callback); 18 | 19 | /** 20 | * Returns a runtime {@link Type} that corresponds to the response type specified in your 21 | * service. 22 | */ 23 | Type responseType(); 24 | 25 | /** 26 | * Builds a new {@link Request} that is identical to the one that will be dispatched 27 | * when the {@link SmartCall} is executed/enqueued. 28 | */ 29 | Request buildRequest(); 30 | 31 | /** 32 | * Create a new, identical call to this one which can be enqueued or executed even if this call 33 | * has already been. 34 | */ 35 | SmartCall clone(); 36 | 37 | /* ================================================================ */ 38 | /* Now it's time for the blocking methods - which can't be smart :( 39 | /* ================================================================ */ 40 | 41 | /** 42 | * Synchronously send the request and return its response. NOTE: No smart caching allowed! 43 | * 44 | * @throws IOException if a problem occurred talking to the server. 45 | * @throws RuntimeException (and subclasses) if an unexpected error occurs creating the request 46 | * or decoding the response. 47 | */ 48 | Response execute() throws IOException; 49 | 50 | /** 51 | * Cancel this call. An attempt will be made to cancel in-flight calls, and if the call has not 52 | * yet been executed it never will be. 53 | */ 54 | void cancel(); 55 | } -------------------------------------------------------------------------------- /smartcache/src/main/java/com/lizubing/smartcache/SmartCallFactory.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcache; 2 | 3 | import com.google.common.reflect.TypeToken; 4 | 5 | import java.io.IOException; 6 | import java.lang.annotation.Annotation; 7 | import java.lang.reflect.Field; 8 | import java.lang.reflect.Method; 9 | import java.lang.reflect.ParameterizedType; 10 | import java.lang.reflect.Type; 11 | import java.util.concurrent.Executor; 12 | 13 | import okhttp3.Request; 14 | import retrofit2.Call; 15 | import retrofit2.CallAdapter; 16 | import retrofit2.Callback; 17 | import retrofit2.Response; 18 | import retrofit2.Retrofit; 19 | 20 | 21 | public class SmartCallFactory extends CallAdapter.Factory { 22 | private final CachingSystem cachingSystem; 23 | private final Executor asyncExecutor; 24 | 25 | public SmartCallFactory(CachingSystem cachingSystem){ 26 | this.cachingSystem = cachingSystem; 27 | this.asyncExecutor = new AndroidExecutor(); 28 | } 29 | 30 | public SmartCallFactory(CachingSystem cachingSystem, Executor executor){ 31 | this.cachingSystem = cachingSystem; 32 | this.asyncExecutor = executor; 33 | } 34 | 35 | @Override 36 | public CallAdapter> get(final Type returnType, final Annotation[] annotations, 37 | final Retrofit retrofit) { 38 | 39 | TypeToken token = TypeToken.of(returnType); 40 | if (token.getRawType() != SmartCall.class) { 41 | return null; 42 | } 43 | 44 | if (!(returnType instanceof ParameterizedType)) { 45 | throw new IllegalStateException( 46 | "SmartCall must have generic type (e.g., SmartCall)"); 47 | } 48 | 49 | final Type responseType = ((ParameterizedType) returnType).getActualTypeArguments()[0]; 50 | final Executor callbackExecutor = asyncExecutor; 51 | 52 | return new CallAdapter>() { 53 | @Override 54 | public Type responseType() { 55 | return responseType; 56 | } 57 | 58 | @Override 59 | public SmartCall adapt(Call call) { 60 | return new SmartCallImpl<>(callbackExecutor, call, responseType(), annotations, 61 | retrofit, cachingSystem); 62 | } 63 | }; 64 | } 65 | 66 | static class SmartCallImpl implements SmartCall{ 67 | private final Executor callbackExecutor; 68 | private final Call baseCall; 69 | private final Type responseType; 70 | private final Annotation[] annotations; 71 | private final Retrofit retrofit; 72 | private final CachingSystem cachingSystem; 73 | private final Request request; 74 | 75 | public SmartCallImpl(Executor callbackExecutor, Call baseCall, Type responseType, 76 | Annotation[] annotations, Retrofit retrofit, CachingSystem cachingSystem){ 77 | this.callbackExecutor = callbackExecutor; 78 | this.baseCall = baseCall; 79 | this.responseType = responseType; 80 | this.annotations = annotations; 81 | this.retrofit = retrofit; 82 | this.cachingSystem = cachingSystem; 83 | 84 | // This one is a hack but should create a valid Response (which can later be cloned) 85 | this.request = buildRequestFromCall(); 86 | } 87 | 88 | /*** 89 | * Inspects an OkHttp-powered Call and builds a Request 90 | * * @return A valid Request (that contains query parameters, right method and endpoint) 91 | */ 92 | private Request buildRequestFromCall(){ 93 | try { 94 | Field argsField = baseCall.getClass().getDeclaredField("args"); 95 | argsField.setAccessible(true); 96 | Object[] args = (Object[]) argsField.get(baseCall); 97 | //retrofit2.0更改了字段(1.0+)requestFactory-->(2.0+)serviceMethod 98 | Field serviceMethodField = baseCall.getClass().getDeclaredField("serviceMethod"); 99 | serviceMethodField.setAccessible(true); 100 | Object requestFactory = serviceMethodField.get(baseCall); 101 | //retrofit2.0更改了方法(1.0+)create-->(2.0+)toRequest 102 | Method createMethod = requestFactory.getClass().getDeclaredMethod("toRequest", Object[].class); 103 | createMethod.setAccessible(true); 104 | return (Request) createMethod.invoke(requestFactory, new Object[]{args}); 105 | }catch(Exception exc){ 106 | // Log.e("buildRequestFromCall"+exc.toString()); 107 | return null; 108 | } 109 | } 110 | 111 | public void enqueueWithCache(final Callback callback) { 112 | Runnable enqueueRunnable = new Runnable() { 113 | @Override 114 | public void run() { 115 | /* Read cache */ 116 | byte[] data = cachingSystem.getFromCache(buildRequest()); 117 | if(data != null) { 118 | final T convertedData = SmartUtils.bytesToResponse(retrofit, responseType, annotations, 119 | data); 120 | Runnable cacheCallbackRunnable = new Runnable() { 121 | @Override 122 | public void run() { 123 | callback.onResponse(baseCall, Response.success(convertedData)); 124 | } 125 | }; 126 | callbackExecutor.execute(cacheCallbackRunnable); 127 | } 128 | 129 | /* Enqueue actual network call */ 130 | baseCall.enqueue(new Callback() { 131 | @Override 132 | public void onResponse(final Call call,final Response response) { 133 | Runnable responseRunnable = new Runnable() { 134 | @Override 135 | public void run() { 136 | if (response.isSuccessful()) { 137 | byte[] rawData = SmartUtils.responseToBytes(retrofit, response.body(), 138 | responseType(), annotations); 139 | cachingSystem.addInCache(response, rawData); 140 | } 141 | callback.onResponse(call, response); 142 | } 143 | }; 144 | // Run it on the proper thread 145 | callbackExecutor.execute(responseRunnable); 146 | } 147 | 148 | @Override 149 | public void onFailure(final Call call, final Throwable t) { 150 | Runnable failureRunnable = new Runnable() { 151 | @Override 152 | public void run() { 153 | callback.onFailure(call,t); 154 | } 155 | }; 156 | callbackExecutor.execute(failureRunnable); 157 | } 158 | 159 | }); 160 | 161 | } 162 | }; 163 | Thread enqueueThread = new Thread(enqueueRunnable); 164 | enqueueThread.start(); 165 | } 166 | 167 | @Override 168 | public void enqueue(final Callback callback) { 169 | if(buildRequest().method().equals("GET")){ 170 | enqueueWithCache(callback); 171 | }else{ 172 | baseCall.enqueue(new Callback() { 173 | @Override 174 | public void onResponse(final Call call, final Response response) { 175 | callbackExecutor.execute(new Runnable() { 176 | @Override 177 | public void run() { 178 | callback.onResponse(call,response); 179 | } 180 | }); 181 | } 182 | 183 | @Override 184 | public void onFailure(final Call call, final Throwable t) { 185 | callbackExecutor.execute(new Runnable() { 186 | @Override 187 | public void run() { 188 | callback.onFailure(call,t); 189 | } 190 | }); 191 | } 192 | }); 193 | } 194 | } 195 | 196 | @Override 197 | public Type responseType() { 198 | return responseType; 199 | } 200 | 201 | @Override 202 | public Request buildRequest() { 203 | return request.newBuilder().build(); 204 | } 205 | 206 | @Override 207 | public SmartCall clone() { 208 | return new SmartCallImpl<>(callbackExecutor, baseCall.clone(), responseType(), 209 | annotations, retrofit, cachingSystem); 210 | } 211 | 212 | @Override 213 | public Response execute() throws IOException { 214 | return baseCall.execute(); 215 | } 216 | 217 | @Override 218 | public void cancel() { 219 | baseCall.cancel(); 220 | } 221 | } 222 | } -------------------------------------------------------------------------------- /smartcache/src/main/java/com/lizubing/smartcache/SmartUtils.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcache; 2 | 3 | import android.util.Log; 4 | 5 | import java.io.IOException; 6 | import java.lang.annotation.Annotation; 7 | import java.lang.reflect.Type; 8 | 9 | import okhttp3.RequestBody; 10 | import okhttp3.ResponseBody; 11 | import okio.Buffer; 12 | import retrofit2.Converter; 13 | import retrofit2.Retrofit; 14 | 15 | public final class SmartUtils { 16 | /* 17 | * TODO: Do an inverse iteration instead so that the latest Factory that supports 18 | * does the job? 19 | */ 20 | @SuppressWarnings("unchecked") 21 | public static byte[] responseToBytes(Retrofit retrofit, T data, Type dataType, 22 | Annotation[] annotations){ 23 | for(Converter.Factory factory : retrofit.converterFactories()){ 24 | if(factory == null) continue; 25 | Converter converter = 26 | (Converter) factory.requestBodyConverter(dataType, annotations,null,retrofit); 27 | 28 | if(converter != null){ 29 | Buffer buff = new Buffer(); 30 | try { 31 | converter.convert(data).writeTo(buff); 32 | }catch(IOException ioException){ 33 | continue; 34 | } 35 | 36 | return buff.readByteArray(); 37 | } 38 | } 39 | return null; 40 | } 41 | 42 | @SuppressWarnings("unchecked") 43 | public static T bytesToResponse(Retrofit retrofit, Type dataType, Annotation[] annotations, 44 | byte[] data){ 45 | for(Converter.Factory factory : retrofit.converterFactories()){ 46 | if(factory == null) continue; 47 | Converter converter = 48 | (Converter) factory.responseBodyConverter(dataType, annotations, retrofit); 49 | 50 | if(converter != null){ 51 | try { 52 | return converter.convert(ResponseBody.create(null, data)); 53 | }catch(IOException | NullPointerException exc){ 54 | Log.e("SmartCall", "", exc); 55 | } 56 | } 57 | } 58 | 59 | return null; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /smartcache/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SmartCache 3 | 4 | -------------------------------------------------------------------------------- /smartcache/src/test/java/com/lizubing/smartcache/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.lizubing.smartcache; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } --------------------------------------------------------------------------------