Android-DiskLruCache

智慧并不产生于学历,而是来自对于知识的终生不懈的追求。这篇文章主要讲述Android-DiskLruCache相关的知识,希望能为你提供帮助。
参考: 1、三分钟学会缓存工具DiskLruCache: 基础使用
2. Android DiskLruCache完全解析, 硬盘缓存的最佳方案:多图片下载setTag避免乱序, 退出程序取消所有下载任务, LruCache和DiskLruCache的结合使用。
3、Android之本地缓存——LruCache( 内存缓存) 与DiskLruCache( 硬盘缓存) 统一框架:二次采样、Lrucache、DiskLruCache的封装。
简介: DiskLruCache是一个十分好用的android缓存工具, 我们可以从GitHub上下载其源码: https://github.com/JakeWharton/DiskLruCache
DiskLruCache所有的数据都存储在/storage/emulated/0/Android/data/应用包名/cache/XXX文件夹中(你也可以修改, 但不建议这样做, 原因请继续往下看), 这个是android系统默认的应用缓存位置, 如果应用被删除, 这个文件也会一起被删除, 避免应用删除后有残留数据的问题。同时, 由于数据没有存储在硬盘里, 所以不会影响系统性能, 在sd卡里, 你可以存储任意多数据。
1、初始化: 由于DiskLruCache是被final修饰的, 因此不可以直接通过new获得它的实例, 我们使用它的open方法获得它的一个实例:
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)

//初始化disklrucache private void initDiskLruCache() { try { File cacheDir = getDiskCacheDir(this, " bitmap" ); if (!cacheDir.exists()) { cacheDir.mkdirs(); } mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(this), 1, 10 * 1024 * 1024); } catch (IOException e) { e.printStackTrace(); } }

open方法需要四个参数, 第一个是缓存文件文件的位置, 通过下面的方法可得到:
private File getDiskCacheDir(Context context, String uniqueName) { String cachePath; //如果sd卡存在并且没有被移除 if (Environment.MEDIA_MOUNTED.equals(Environment .getExternalStorageState()) || !Environment.isExternalStorageRemovable()) { cachePath = context.getExternalCacheDir().getPath(); } else { cachePath = context.getCacheDir().getPath(); } return new File(cachePath + File.separator + uniqueName); }

第二个参数是应用程序的版本号, 要传入版本号是因为如果应用升级缓存会被清除掉。通过下面的方法可以获得程序的版本号:
private int getAppVersion(Context context) { try { PackageInfo info = context.getPackageManager().getPackageInfo( context.getPackageName(), 0); return info.versionCode; } catch (NameNotFoundException e) { e.printStackTrace(); } return 1; }

第三个参数表示同一个key可以对应多少个缓存文件, 一般情况下我们都是传1, 这样key和缓存文件一一对应, 查找和移除都会比较方便。
第四个参数表示最大可以缓存多少字节的数据。
2、缓存数据 打开了DiskLruCache之后, 我们可以看看怎么向DiskLruCache中缓存数据:
先来看看从网上down一张图片:
private boolean downloadImg(final String urlStr, final OutputStream outputStream) { HttpURLConnection conn = null; BufferedOutputStream out = null; BufferedInputStream in = null; try { URL url = new URL(urlStr); conn = (HttpURLConnection) url.openConnection(); in = new BufferedInputStream(conn.getInputStream(), 8 * 1024); out = new BufferedOutputStream(outputStream, 8 * 1024); int len = 0; while ((len = in.read()) != -1) { out.write(len); } return true; } catch (IOException e) { e.printStackTrace(); } finally { if (conn != null) conn.disconnect(); try { if (out != null) out.close(); } catch (IOException e) { e.printStackTrace(); } try { if (in != null) in.close(); } catch (IOException e) { e.printStackTrace(); } } return false; }

这是一个简单的联网down图片代码, 拿到图片后就可以缓存到本地了, 但是对于每一个存储资源都需要有一个key,这个key要是唯一的, 而且这个key最长120个字符, 且只能包括a-z,0-9,下划线以及减号, 一次我们可以采用java中的UUID来得到key,也可以使用MD5加密网址得到一个key,我这里采用md5, 方法如下:
public class MD5Util {public final static String md5(String pwd) { //用于加密的字符 char md5String[] = { ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' , ' A' , ' B' , ' C' , ' D' , ' E' , ' F' }; try { //使用平台的默认字符集将此 String 编码为 byte序列, 并将结果存储到一个新的 byte数组中 byte[] btInput = pwd.getBytes(); // 获得指定摘要算法的 MessageDigest对象, 此处为MD5 //MessageDigest类为应用程序提供信息摘要算法的功能, 如 MD5 或 SHA 算法。 //信息摘要是安全的单向哈希函数, 它接收任意大小的数据, 并输出固定长度的哈希值。 MessageDigest mdInst = MessageDigest.getInstance(" MD5" ); //System.out.println(mdInst); //MD5 Message Digest from SUN, < initialized> //MessageDigest对象通过使用 update方法处理数据, 使用指定的byte数组更新摘要 mdInst.update(btInput); //System.out.println(mdInst); //MD5 Message Digest from SUN, < in progress> // 摘要更新之后, 通过调用digest( ) 执行哈希计算, 获得密文 byte[] md = mdInst.digest(); //System.out.println(md); // 把密文转换成十六进制的字符串形式 int j = md.length; //System.out.println(j); char str[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i+ + ) {//i = 0 byte byte0 = md[i]; //95 str[k+ + ] = md5String[byte0 > > > 4 & 0xf]; //5 str[k+ + ] = md5String[byte0 & 0xf]; //F }//返回经过加密后的字符串 return new String(str); } catch (Exception e) { e.printStackTrace(); return null; } } }

现在万事俱备, 我们来把图片缓存起来, 由于联网是耗时操作, 所以要在新线程中完成, 完整的方法如下:
private void cacheImg() { new Thread(new Runnable() {@ Override public void run() { String key = MD5Util.md5(IMGIP); try { DiskLruCache.Editor editor = mDiskLruCache.edit(key); if (editor != null) { OutputStream out = editor.newOutputStream(0); if (downloadImg(IMGIP, out)) { //提交 editor.commit(); } else { //撤销操作 editor.abort(); } } }/** * 这个方法用于将内存中的操作记录同步到日志文件( 也就是journal文件) 当中。 * 这个方法非常重要, 因为DiskLruCache能够正常工作的前提就是要依赖于journal文件中的内容。 * 并不是每次写入缓存都要调用一次flush()方法的, 频繁地调用并不会带来任何好处, * 只会额外增加同步journal文件的时间。 * 比较标准的做法就是在Activity的onPause()方法中去调用一次flush()方法就可以了 */ mDiskLruCache.flush(); } catch (IOException e) { e.printStackTrace(); } } }).start(); }

editor.newOutputStream(0); 方法有一个参数, 查看源码我们知道这个参数必须大于0并且小于valueCount, 前文中valueCount我们已经设置为1了, 所以这里只能取值0。这个时候打开你的缓存文件夹, /storage/emulated/0/Android/data/应用包名/cache/XXX, 里边已经有了我们缓存的数据了:
Android-DiskLruCache

文章图片

3、读取缓存 好了, 数据存下来了, 接下来就是读取, 每一个缓存文件都对应一个key, 读取就是根据这个key来读取:
private void showImg() { String key = MD5Util.md5(IMGIP); try { DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key); if(snapShot!= null){ InputStream is = snapShot.getInputStream(0); Bitmap bitmap = BitmapFactory.decodeStream(is); im.setImageBitmap(bitmap); } } catch (IOException e) { e.printStackTrace(); } }

读取的时候我们最先拿到的是一个Snapshot 对象, 再根据我们之前传入的参数0拿到缓存文件的流, 最后把流转换为图片。
到这里大家可能就明白了, 之前的editor.newOutputStream(0); 方法为什么会有一个0的参数了, 相当于一个标识, 读取时也传入参数0才能读到我们想要的数据。( 加入我们的key与缓存文件不是一一对应, 也就是我们一开始的open方法中传入的不是valueCount的值不是1, 那么一个key对应多个缓存文件我们要怎么区分? 就是通过这种方式, 有兴趣的同学查看源码就一目了然了) 。
4、清除缓存
private void clearCache() { String key = MD5Util.md5(IMGIP); try { mDiskLruCache.remove(key); } catch (IOException e) { e.printStackTrace(); } }

根据缓存文件的key, 调用remove方法, 将该缓存文件移除。
5、获取缓存大小 像凤凰新闻客户端中显示缓存大小, 这个数值我们可以通过size()方法直接拿到:
private void getCacheSize() { tv.setText(mDiskLruCache.size()+ " " ); }

6、清除所有数据
private void deleteAll() { /** * 这个方法用于将所有的缓存数据全部删除 * 其实只需要调用一下DiskLruCache的delete()方法就可以实现了。 * 会删除包括日志文件在内的所有文件 */ try { mDiskLruCache.delete(); } catch (IOException e) { e.printStackTrace(); } }

7、关闭DiskLruCache 所有功能都完成之后, 我们要记得在onDestory方法中关闭DiskLruCache。
@ Override protected void onDestroy() { super.onDestroy(); /** * 这个方法用于将DiskLruCache关闭掉, 是和open()方法对应的一个方法。 * 关闭掉了之后就不能再调用DiskLruCache中任何操作缓存数据的方法, * 通常只应该在Activity的onDestroy()方法中去调用close()方法。 */ try { mDiskLruCache.close(); } catch (IOException e) { e.printStackTrace(); } }

郭霖大神的demo: 布局:
activity_main.xml
< LinearLayout xmlns:android= " http://schemas.android.com/apk/res/android" xmlns:tools= " http://schemas.android.com/tools" android:layout_width= " match_parent" android:layout_height= " match_parent" > < GridView android:id= " @ + id/photo_wall" android:layout_width= " match_parent" android:layout_height= " match_parent" android:columnWidth= " @ dimen/image_thumbnail_size" android:gravity= " center" android:horizontalSpacing= " @ dimen/image_thumbnail_spacing" android:numColumns= " auto_fit" android:stretchMode= " columnWidth" android:verticalSpacing= " @ dimen/image_thumbnail_spacing" > < /GridView> < /LinearLayout>

MainActivity.java
package com.example.photoswalldemo; import android.app.Activity; import android.os.Bundle; import android.view.ViewTreeObserver; import android.widget.GridView; /** * 照片墙主活动, 使用GridView展示照片墙。 * * http://blog.csdn.net/guolin_blog/article/details/34093441 * Android照片墙完整版, 完美结合LruCache和DiskLruCache * * http://blog.csdn.net/guolin_blog/article/details/28863651 *Android DiskLruCache完全解析, 硬盘缓存的最佳方案 * * * @ author guolin */ public class MainActivity extends Activity {/** * 用于展示照片墙的GridView */ private GridView mPhotoWall; /** * GridView的适配器 */ private PhotoWallAdapter mAdapter; private int mImageThumbSize; private int mImageThumbSpacing; @ Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mImageThumbSize = getResources().getDimensionPixelSize( R.dimen.image_thumbnail_size); mImageThumbSpacing = getResources().getDimensionPixelSize( R.dimen.image_thumbnail_spacing); mPhotoWall = (GridView) findViewById(R.id.photo_wall); mAdapter = new PhotoWallAdapter(this, 0, Images.imageThumbUrls, mPhotoWall); mPhotoWall.setAdapter(mAdapter); /*通过getViewTreeObserver()的方式监听View的布局事件, 当布局完成以后, 我们重新修改一下GridView中子View的高度, 以保证子View的宽度和高度可以保持一致。*/ mPhotoWall.getViewTreeObserver().addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() {@ Override public void onGlobalLayout() { final int numColumns = (int) Math.floor(mPhotoWall.getWidth() / (mImageThumbSize + mImageThumbSpacing)); //Math.floor:求一个浮点数的地板,就是求一个最接近它的整数,它的值小于或等于这个浮点数。 if (numColumns > 0) { int columnWidth = (mPhotoWall.getWidth() / numColumns) - mImageThumbSpacing; mAdapter.setItemHeight(columnWidth); mPhotoWall.getViewTreeObserver().removeGlobalOnLayoutListener(this); } } }); }@ Override protected void onPause() { super.onPause(); mAdapter.fluchCache(); }@ Override protected void onDestroy() { super.onDestroy(); // 退出程序时结束所有的下载任务 mAdapter.cancelAllTasks(); }}

item布局:
photo_layout.xml
< RelativeLayout xmlns:android= " http://schemas.android.com/apk/res/android" xmlns:tools= " http://schemas.android.com/tools" android:layout_width= " wrap_content" android:layout_height= " wrap_content" > < ImageView android:id= " @ + id/photo" android:layout_width= " match_parent" android:layout_height= " match_parent" android:layout_centerInParent= " true" android:scaleType= " fitXY" /> < /RelativeLayout>

PhotoWallAdapter.java
package com.example.photoswalldemo; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashSet; import java.util.Set; import libcore.io.DiskLruCache; import libcore.io.DiskLruCache.Snapshot; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.os.Environment; import android.util.LruCache; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.GridView; import android.widget.ImageView; /** * GridView的适配器, 负责异步从网络上下载图片展示在照片墙上。 * < p> * 每次加载图片的时候都优先去【内存缓存】当中读取, 当读取不到的时候则回去【硬盘缓存】中读取, * 而如果硬盘缓存仍然读取不到的话, 就从【网络】上请求原始数据。不管是从硬盘缓存还是从网络获取, * 读取到了数据之后都应该添加到内存缓存当中, 这样的话我们下次再去读取图片的时候就能迅速从内存当中读取到, * 而如果该图片从内存中被移除了的话, 那就重复再执行一遍上述流程就可以了。 * < p> * 你完全不需要担心缓存的数据过多从而占用SD卡太多空间的问题, * DiskLruCache会根据我们在调用open()方法时设定的缓存最大值来自动删除多余的缓存。 * 只有你确定某个key对应的缓存内容已经过期, 需要从网络获取最新数据的时候才应该调用remove()方法来移除缓存。 * * @ author guolin */ public class PhotoWallAdapter extends ArrayAdapter< String> {/** * 记录所有正在下载或等待下载的任务。 */ private Set< BitmapWorkerTask> taskCollection; /** * 图片缓存技术的核心类, 用于缓存所有下载好的图片, 在程序内存达到设定值时会将最少最近使用的图片移除掉。 */ private LruCache< String, Bitmap> mMemoryCache; /** * 图片硬盘缓存核心类。 */ private DiskLruCache mDiskLruCache; /** * GridView的实例 */ private GridView mPhotoWall; /** * 记录每个子项的高度。 */ private int mItemHeight = 0; public PhotoWallAdapter(Context context, int textViewResourceId, String[] objects, GridView photoWall) { super(context, textViewResourceId, objects); mPhotoWall = photoWall; taskCollection = new HashSet< BitmapWorkerTask> (); /*首先在PhotoWallAdapter的构造函数中, 我们初始化了LruCache类, 并设置了内存缓存容量为程序最大可用内存的1/8, 紧接着调用了DiskLruCache的open()方法来创建实例, 并设置了硬盘缓存容量为10M, 这样我们就把LruCache和DiskLruCache的初始化工作完成了。*/// 获取应用程序最大可用内存 int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheSize = maxMemory / 8; // 设置图片缓存大小为程序最大可用内存的1/8mMemoryCache = new LruCache< String, Bitmap> (cacheSize) { @ Override protected int sizeOf(String key, Bitmap bitmap) { return bitmap.getByteCount(); } }; try { // 获取图片缓存路径 File cacheDir = getDiskCacheDir(context, " thumb" ); if (!cacheDir.exists()) { cacheDir.mkdirs(); } // 创建DiskLruCache实例, 初始化缓存数据 mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, 10 * 1024 * 1024); //public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize) //open()方法接收四个参数, 第一个参数指定的是数据的缓存地址, 第二个参数指定当前应用程序的版本号, // 第三个参数指定同一个key可以对应多少个缓存文件, 基本都是传1, 第四个参数指定最多可以缓存多少字节的数据。 } catch (IOException e) { e.printStackTrace(); } }@ Override public View getView(int position, View convertView, ViewGroup parent) { final String url = getItem(position); View view; if (convertView = = null) { view = LayoutInflater.from(getContext()).inflate(R.layout.photo_layout, null); } else { view = convertView; } final ImageView imageView = (ImageView) view.findViewById(R.id.photo); if (imageView.getLayoutParams().height != mItemHeight) { imageView.getLayoutParams().height = mItemHeight; } // 给ImageView设置一个Tag, 保证异步加载图片时不会乱序 imageView.setTag(url); imageView.setImageResource(R.drawable.empty_photo); loadBitmaps(imageView, url); return view; }/** * 将一张图片存储到LruCache中。 * * @ param keyLruCache的键, 这里传入图片的URL地址。 * @ param bitmap LruCache的键, 这里传入从网络上下载的Bitmap对象。 */ public void addBitmapToMemoryCache(String key, Bitmap bitmap) { if (getBitmapFromMemoryCache(key) = = null) { mMemoryCache.put(key, bitmap); } }/** * 从LruCache中获取一张图片, 如果不存在就返回null。 * * @ param key LruCache的键, 这里传入图片的URL地址。 * @ return 对应传入键的Bitmap对象, 或者null。 */ public Bitmap getBitmapFromMemoryCache(String key) { return mMemoryCache.get(key); }/** * 加载Bitmap对象。此方法会在LruCache中检查所有屏幕中可见的ImageView的Bitmap对象, * 如果发现任何一个ImageView的Bitmap对象不在缓存中, 就会开启异步线程去下载图片。 */ public void loadBitmaps(ImageView imageView, String imageUrl) { try { Bitmap bitmap = getBitmapFromMemoryCache(imageUrl); if (bitmap = = null) { BitmapWorkerTask task = new BitmapWorkerTask(); taskCollection.add(task); task.execute(imageUrl); } else { if (imageView != null & & bitmap != null) { imageView.setImageBitmap(bitmap); } } } catch (Exception e) { e.printStackTrace(); } }/** * 取消所有正在下载或等待下载的任务。 */ public void cancelAllTasks() { if (taskCollection != null) { for (BitmapWorkerTask task : taskCollection) { task.cancel(false); } } }/** * 根据传入的uniqueName获取硬盘缓存的路径地址。 * 当SD卡存在或者SD卡不可被移除的时候, 就调用getExternalCacheDir()方法来获取缓存路径, 否则就调用getCacheDir()方法来获取缓存路径。 * 前者获取到的就是 /sdcard/Android/data/< application package> /cache 这个路径, * 而后者获取到的是 /data/data/< application package> /cache 这个路径。 */ public File getDiskCacheDir(Context context, String uniqueName) { String cachePath; if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) { cachePath = context.getExternalCacheDir().getPath(); } else { cachePath = context.getCacheDir().getPath(); } return new File(cachePath + File.separator + uniqueName); }/** * 获取当前应用程序的版本号。 */ public int getAppVersion(Context context) { try { PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); return info.versionCode; } catch (NameNotFoundException e) { e.printStackTrace(); } return 1; }/** * 设置item子项的高度。 */ public void setItemHeight(int height) { if (height = = mItemHeight) { return; } mItemHeight = height; notifyDataSetChanged(); }/** * 使用MD5算法对传入的key进行加密并返回。MD5第一步 * < p> * 直接使用URL来作为key? 不太合适, 因为图片URL中可能包含一些特殊字符, 这些字符有可能在命名文件时是不合法的。 * 其实最简单的做法就是将图片的URL进行MD5编码, 编码后的字符串肯定是唯一的, 并且只会包含0-F这样的字符, 完全符合文件的命名规则。 */ public String hashKeyForDisk(String key) { String cacheKey; try { final MessageDigest mDigest = MessageDigest.getInstance(" MD5" ); mDigest.update(key.getBytes()); cacheKey = bytesToHexString(mDigest.digest()); } catch (NoSuchAlgorithmException e) { cacheKey = String.valueOf(key.hashCode()); } return cacheKey; }/** * 将缓存记录同步到journal文件中。 */ public void fluchCache() { if (mDiskLruCache != null) { try { mDiskLruCache.flush(); } catch (IOException e) { e.printStackTrace(); } } }/* * MD5第二步 * */ private String bytesToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i+ + ) { String hex = Integer.toHexString(0xFF & bytes[i]); if (hex.length() = = 1) { sb.append(' 0' ); } sb.append(hex); } return sb.toString(); }/** * 异步下载图片的任务。 * * @ author guolin */ class BitmapWorkerTask extends AsyncTask< String, Void, Bitmap> {/** * 图片的URL地址 */ private String imageUrl; @ Override protected Bitmap doInBackground(String... params) { imageUrl = params[0]; FileDescriptor fileDescriptor = null; FileInputStream fileInputStream = null; Snapshot snapShot = null; try { // 生成图片URL对应的key final String key = hashKeyForDisk(imageUrl); //只包含0-F // 查找key对应的缓存 snapShot = mDiskLruCache.get(key); if (snapShot = = null) { // 如果没有找到对应的缓存, 则准备从网络上请求数据, 并写入缓存 DiskLruCache.Editor editor = mDiskLruCache.edit(key); if (editor != null) { OutputStream outputStream = editor.newOutputStream(0); if (downloadUrlToStream(imageUrl, outputStream)) { editor.commit(); } else { editor.abort(); } } // 缓存被写入后, 再次查找key对应的缓存 snapShot = mDiskLruCache.get(key); }//if (snapShot != null) { //fileInputStream = (FileInputStream) snapShot.getInputStream(0); ////返回FileDescriptor的标识连接到正在使用此文件输入流文件系统的实际文件的对象。 //fileDescriptor = fileInputStream.getFD(); //} // 将缓存数据解析成Bitmap对象 Bitmap bitmap = null; //if (fileDescriptor != null) { //bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor); //} if (snapShot != null) { bitmap = BitmapFactory.decodeStream(snapShot.getInputStream(0)); } if (bitmap != null) { // 将Bitmap对象添加到内存缓存LruCache当中 addBitmapToMemoryCache(params[0], bitmap); } return bitmap; } catch (IOException e) { e.printStackTrace(); } finally { if (fileDescriptor = = null & & fileInputStream != null) { try { fileInputStream.close(); } catch (IOException e) { } } } return null; }@ Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); // 根据Tag找到相应的ImageView控件, 将下载好的图片显示出来。 ImageView imageView = (ImageView) mPhotoWall.findViewWithTag(imageUrl); if (imageView != null & & bitmap != null) { imageView.setImageBitmap(bitmap); } taskCollection.remove(this); }/** * 建立HTTP请求, 并获取Bitmap对象。 * * @ param urlString 图片的URL地址 * @ return 解析后的Bitmap对象 */ private boolean downloadUrlToStream(String urlString, OutputStream outputStream) { HttpURLConnection urlConnection = null; BufferedOutputStream out = null; BufferedInputStream in = null; try { final URL url = new URL(urlString); urlConnection = (HttpURLConnection) url.openConnection(); in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024); out = new BufferedOutputStream(outputStream, 8 * 1024); int b; while ((b = in.read()) != -1) { out.write(b); } return true; } catch (final IOException e) { e.printStackTrace(); } finally { if (urlConnection != null) { urlConnection.disconnect(); } try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (final IOException e) { e.printStackTrace(); } } return false; }}}

【Android-DiskLruCache】图片URL类:
package com.example.photoswalldemo; public class Images {public final static String[] imageThumbUrls = new String[] { " https://img-my.csdn.net/uploads/201407/26/1406383299_1976.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383291_6518.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383291_8239.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383290_9329.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383290_1042.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383275_3977.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383265_8550.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383264_3954.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383264_4787.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383264_8243.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383248_3693.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383243_5120.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383242_3127.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383242_9576.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383242_1721.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383219_5806.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383214_7794.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383213_4418.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383213_3557.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383210_8779.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383172_4577.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383166_3407.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383166_2224.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383166_7301.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383165_7197.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383150_8410.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383131_3736.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383130_5094.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383130_7393.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383129_8813.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383100_3554.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383093_7894.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383092_2432.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383092_3071.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383091_3119.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383059_6589.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383059_8814.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383059_2237.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383058_4330.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406383038_3602.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382942_3079.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382942_8125.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382942_4881.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382941_4559.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382941_3845.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382924_8955.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382923_2141.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382923_8437.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382922_6166.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382922_4843.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382905_5804.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382904_3362.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382904_2312.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382904_4960.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382900_2418.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382881_4490.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382881_5935.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382880_3865.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382880_4662.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382879_2553.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382862_5375.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382862_1748.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382861_7618.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382861_8606.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382861_8949.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382841_9821.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382840_6603.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382840_2405.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382840_6354.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382839_5779.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382810_7578.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382810_2436.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382809_3883.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382809_6269.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382808_4179.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382790_8326.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382789_7174.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382789_5170.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382789_4118.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382788_9532.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382767_3184.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382767_4772.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382766_4924.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382766_5762.jpg" , " https://img-my.csdn.net/uploads/201407/26/1406382765_7341.jpg" }; }


    推荐阅读