DiskLruCache硬盘缓存技术详解

上次讲了使用内存缓存LruCache去加载很多图片而不造成OOM,而这种缓存的特点是在应用程序运行时管理内存中的资源(图片)的存储和释放,如果LruCache中有一张图片被释放了,再次加载该图片时需要重新从网络上下载下来,这就显得废流量不说,而且费时,网络不好的状况下用户需要等待,而且在没有网络的情况下不会显示任何数据。

那么怎样才能解决这种情况呢?答案就是加入硬盘缓存DiskLruCache。

1、什么是硬盘缓存呢?

顾名思义,就是把从网络上加载的数据存储在本地硬盘上,当再次加载这些数据时候,通过一系列判断本地是否有该数据,就不会从先网络上加载,而是从本地硬盘缓存中拿取数据,这样即使在没有网络情况下,也可以把数据显示出来。举个例子:比如网易新闻app,我们打开客户端后开始浏览新闻,之后发现在手机没有联网的情况下,之前浏览的界面还是能正常的显示出来,这显然就是用到了硬盘缓存DiskLruCache技术,其实硬盘缓存技术在诸多app中运用了,比如一些视频类app、小说类app。。。然而,DiskLruCache并不是Google官方编写的,不过获得了Google的认可,我们要使用它需要在Google官网上去下载这个类:android.googlesource.com/platform/libcore/+/jb-mr2-release/luni/src/main/java/libcore/io/DiskLruCache.java

然后在项目目录下新建一个libcore.io包,把下载好的DiskLruCache拷贝到包里面就行。有的没有翻墙的童鞋可以看这里我上传的DiskLruCache地址是:点击下载DiskLruCache

2、硬盘缓存中缓存的数据存储在哪里呢?

一般一个应用程序内的缓存目录有两个:

1、一个在外置sd卡中,我们可以通过context.getExternalCacheDir().getPath()得到sd中的缓存目录,即:/mnt/sdcard/Android/data/<--appPackageName-->/cache

2、一个在应用的安装目录下,我们可以通过context.getCacheDir().getPath()得到应用内的缓存目录,即:

/data/data/<--appPackageName-->/cache

我们可以看到在cache目录下我们还可以对我们缓存的数据进行分类,比如图片为bitmap,文本为strings等。

那么有人就有疑问了,两个缓存目录?那用哪个呢?

这个问题没有具体的答案的,一般情况下我们会用外置sb卡中的缓存目录,因为这样可以节省手机的内存空间,即使缓存目录的大小有几十兆也不会对用户有什么影响。那么万一有的用户没有插入sd卡呢?这时我们就需要用安装目录下的缓存目录了。所以,我们在设置缓存目录时都会有个判断sd是否插入来设置缓存目录,这个代码可以这样写:

/**
     * @param cacheDirName - 缓存的最终目录文件夹名称
     * @return - 获取硬盘缓存的目录
     */
    private File getDiskLruCacheDir(Context context, String cacheDirName) {
        String cachePath;
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
                || !Environment.isExternalStorageRemovable()) {
            cachePath = context.getExternalCacheDir().getPath();
        } else {
            cachePath = context.getCacheDir().getPath();
        }
        File file = new File(cachePath + "/" + cacheDirName);
        if (!file.exists()) {
            file.mkdirs();
        }
        return file;
    }

3、硬盘缓存中缓存的数据格式是什么样子的呢?

我们来打开一个缓存目录来看一下:

一眼看去发现除了我用红框框圈住的文件外其它的全部是名字用字母和数字组成的文件。这样看我们当然看不懂这些文件代表什么意思了,其实,这些文件就是我们应用程序的缓存文件,各个类型的缓存数据都是存储在这样的一个文件中,比如我们缓存图片,那么每一张图片就是对应这样的一个文件,它的名字往往就是通过md5编码得来的,名字也就是key值,通过key值我们就可以得到该缓存文件了,进而把数据显示在界面上。

好了,说了那么多,还没说到我用红框框圈住的那个文件呢,也就是journal,该文件其实作用大着呢,它是DiskLruCache的一个日志文件,应用程序对每条数据(图片,文本等)的操作记录都存放在这个文件中,通俗的说我们对缓存文件的写入、读取、缓存的文件大小等记录都会保存在这个日志文件中。

那么,journal里面是什么样的呢?我们随便打开一个应用的缓存目录后发现是这样的:

我们来分别对每一行进行分析吧:

1、想都不用想,就是告诉我们该缓存用的是DiskLruCache。

2、DiskLruCache的版本号。

3、应用程序的版本号。

4、在DiskLruCache.open()方法中传入,表示一个key可以对应几个缓存文件,一般我们都传1,表示一key一Value。

5、DIRTY开头,后面紧跟md5编码的key值,也就是缓存文件的名字,表示我们正在向缓存文件中写入一条数据,缓存文件的名字为后面的key值,可能写入成功,也可能写入失败,故标记为dirty。

6、CLEAN开头,后面紧跟缓存文件的名称,表示该数据写入成功了,再后面又有一组数字,其实该组数字是我们写入的数据字节大小,比如我们写入的是图片,那说明该图片的大小为17352个字节。

7、READ开头,后面紧跟缓存文件的名称,表示我们读取了该名称的缓存文件的数据。

8、这就不用说了吧,和上面的一样,表示正在写入一条数据到缓存文件中。

9、写入成功。

10、读取缓存文件的数据。

11、读取缓存文件的数据。

好了,journal文件就分析完了,其实任何使用了DiskLruCache技术的journal日志文件格式都是这样的,一一记录着缓存文件的操作记录。

4、硬盘缓存DiskLruCache怎么用呢?

打开DiskLruCache的源码,卧槽,太多了,贴上来怎么看?那就讲讲常用的方法吧。

1、怎么创建DiskLruCache对象呢?

首先进源码中看到,它的构造方法被private修饰,显然在外部不能通过new来创建对象,那就来看看它内部在哪个方法中new了,发现在一个公共静态方法open(...)中创建了DiskLruCache对象并返回,可知我们需要通过DiskLruCache.open(...)来创建一个DiskLruCache对象。不过为什么要这样做呢而不能直接new出来呢,看open()方法的源码发现:它主要是在维护journal日志文件,当每次我们调用open()方法时去创建DiskLruCache对象,open()方法内部会有判断该缓存目录下的journal日志文件是否存在,如果存在我们对缓存文件进行操作时的操作记录将会append在journal后面,如果不存在,那么将会重新创建一个journal日志文件。

好了,我们直接来看看open()方法吧:

public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)

需要传入四个参数,意思分别为:

  • directory - 我们设置的缓存目录,最好用刚刚我在第二点上写的那个方法得到的缓存目录。
  • appVersion - 应用程序的版本号,可以这样得到:
    PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
    int versionID = info.versionCode;
  • valueCount - 就是一个key可以对应几个缓存文件,一般传1。
  • maxSize - 就是缓存空间的大小,传入的是字节,当缓存空间存储的缓存内容超过该大小后,DiskLruCache会自动清除一些缓存文件,来腾出空间进行缓存。一般我们可以根据需要缓存的内容来定,大多情况下可以设为10*1024*1024,也就是10M。

好了,各个参数的意思都知道了,我们就来看看怎么创建DiskLruCache吧:

 DiskLruCache mBitmapDiskLruCache = null;
        File file = getDiskLruCacheDir(this, "bitmap");
        int versionID = getAppVersionNum(this);
        try {
            mBitmapDiskLruCache = DiskLruCache.open(file, versionID, 1, 10 * 1024 * 1024);
        } catch (IOException e) {
            e.printStackTrace();
        }

getDiskLruCacheDir():

    private File getDiskLruCacheDir(Context context, String cacheDirName) {
        String cachePath;
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
                || !Environment.isExternalStorageRemovable()) {
            cachePath = context.getExternalCacheDir().getPath();
        } else {
            cachePath = context.getCacheDir().getPath();
        }
        File file = new File(cachePath + "/" + cacheDirName);
        if (!file.exists()) {
            file.mkdirs();
        }
        return file;
    }

getAppVersionNum():

private int getAppVersionNum(Context context) {
        try {
            PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
            return info.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return 1;
    }

好了,DiskLruCache对象就创建好了,接下来就是根据我们创建的DiskLruCache对象来对进行数据的一系列操作了。

2、将数据写入硬盘缓存中

将数据写入硬盘缓存中,我们需要用到的一个方法就是edit()方法:

public Editor edit(String key)

可以看到我们需要传入一个key值,这就是缓存文件的名称了,这个key值一般情况下我们会采用md5(url)的形式,就是把数据(图片等)对应的url进行md5进行编码加密后即可。

进行md5编码的代码如下:

public class String2MD5Tools {
    /**
     * @param key
     * @return
     * 对key进行MD5加密并返回加密过的散列值
     */
    public static 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;
    }

    private static 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();
    }
}

然后通过调用hashKeyForDisk就可以对url进行编码了:

String key = String2MD5Tools.hashKeyForDisk(url);

好了,回到edit()方法上,该方法返回的是一个DiskLruCache.Editor类型的对象,Editor是DiskLruCache的一个成员内部类:

通常常用的就是上图标记的那几个方法,再回到刚刚那个edit()方法,通过它我们得到了一个Editor对象,然后我们可以调用mEditor.newOutputStream(int)得到输出流,我们再往输出流中写入我们要缓存的数据,如果写入成功了,最后通过调用mEditor.commit()方法来提交,这时才真正的把数据写入到了缓存文件中,如果刚刚写入失败了,则调用mEditor.abort()来放弃这次写入。

【注意】刚刚我们调用mEditor.newOutputStream(int)得到输出流时候,需要传入一个int类型的参数,该参数的意思就是表示把数据写入第几个缓存文件中,因为刚刚开始在open()方法中我们传入的那个1表示一个key对应一个缓存文件,所以这里传入0表示写入第一个缓存文件中,因为index是从0开始的。所以这个地方需要注意一下。

好了,说了那么多,我们来看看写入数据到缓存文件中完整的代码吧:

DiskLruCache.Editor editor = mBitmapDiskLruCache.edit(String2MD5Tools.hashKeyForDisk(url));
            if (editor != null) {
                OutputStream outputStream = editor.newOutputStream(0);//得到输出流,往里面写数据
                bitmap = downloadBitmap(url, outputStream);//把刚刚下载的图片存入硬盘缓存中,对应的key值为md5(url)
                if (bitmap != null) {
                    editor.commit();//提交表示写入缓存成功
                }else{
                    editor.abort();//表示放弃此次写入
                }
            }

写入成功后,我们就可以在缓存目录下看到多出一个名字由md5编码的文件了。

其中downloadBitmap()方法就是一个普通的从网络上下载图片的方法:

/**
     * 从网络上下载图片,下载时候把下载的图片写入OutputStream中
     * @param urlStr
     * @return
     */
    private Bitmap downloadBitmap(String urlStr, OutputStream outputStream) {
        HttpURLConnection connection = null;
        BufferedOutputStream bufferedOutputStream;
        Bitmap bitmap = null;
        try {
            URL url = new URL(urlStr);
            connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(5000);
            connection.setReadTimeout(5000);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.connect();
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                InputStream mInputStream = connection.getInputStream();
                bitmap = BitmapFactory.decodeStream(mInputStream);
                bufferedOutputStream = new BufferedOutputStream(outputStream);
                int len=-1;
                byte[] by = new byte[1024];
                while ((len = mInputStream.read(by)) != -1) {
                    bufferedOutputStream.write(by, 0, len);
                }
                bufferedOutputStream.flush();
                bufferedOutputStream.close();
                mInputStream.close();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
        return bitmap;
    }

当然,上述写入数据到缓存的过程需要放到另外一个线程中去执行,原因肯定不用我多说,因为有请求网络的操作。

3、从硬盘缓存中读取数据

从硬盘缓存中读取数据其实要简单写,就是通过get()方法来读取的,我们来看看get方法:

public synchronized Snapshot get(String key)

可知它需要传入一个key值,这里我想都知道怎么传入这个key值吧,就是我们通过md5(url)编码后的key值,该方法是根据我们传入的key值来查找对应了缓存文件名称,如果找到了key和缓存文件名一样那就返回一个Snapshot类型的对象,如果没找到就返回null。

现在主要讲讲Snapshot对象是什么鬼?

它也是DiskLruCache的一个成员内部类,其中主要用的方法就是getInputStream(int);顾名思义,该方法就是得到传入的key对应的缓存文件的输入流,通过输入流我们可以获取缓存文件中的信息,其中参数int也是传入0,就不多说了,下面我们来看看读取缓存数据的完整代码:

DiskLruCache.Snapshot snapshot = mBitmapDiskLruCache.get(String2MD5Tools.hashKeyForDisk(url));
            if (snapshot != null) {//如果硬盘缓存中存在该缓存文件
                InputStream inputStream = snapshot.getInputStream(0);//获得该缓存文件的输入流
                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);//把输入流解析成Bitmap
                if (bitmap != null) {
                    mImageView.setImageBitmap(bitmap);
            }else{
                //硬盘缓存中不存在图片缓存则开启一个线程去下载图片
                //do sthing
            }

4、从硬盘缓存中删除指定key值的缓存文件

public synchronized boolean remove(String key)

代码很简单,传入指定的key即可删除对应名称的缓存文件:

boolean flag = mBitmapDiskCache.remove(String2MD5Tools.hashKeyForDisk(url));
if(flag){
//删除成功
}else{
//删除失败
}

5、获取当前缓存目录下所使用的内存大小和清空缓存数据

获取缓存目录下总缓存文件的大小是通过size()方法返回,返回的是long类型的字节数,我们可以这样用:

long totalCacheSize = mBitmapDiskLruCache.size();

像很多应用都会在设置界面下显示该app的缓存大小,其实就是通过它得到的,然后我们可以手动清除它,清除全部的缓存数据是使用:

mBitmapDiskLruCache.delete();

来清空缓存数据。

6、同步缓存文件的操作记录至journal和关闭缓存

我们在上面讲了写入缓存数据、读取缓存数据、移除缓存数据等,那么上面的这些方法是通过实际操作来达到效果的,而记录同步缓存文件的操作信息则由journal文件来完成的,DiskLruCache能够正常的工作完全是依赖journal文件,所以在上述操作做完后同步操作记录尤为重要,同步操作记录是通过:

mBitmapDiskLruCache.flush();

完成的,通常我们会在OnPause()方法中调用它,表示操作全部结束后进行同步记录。

而关闭缓存则是在用完结束后进行关闭:

mBitmapDiskLruCache.close();

通常我们会在onDestroy()方法中调用它,那么完整的代码为:

@Override
    protected void onPause() {
        super.onPause();
        try {
            if (mBitmapDiskLruCache != null) {
                mBitmapDiskLruCache.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        try {
            if (mBitmapDiskLruCache != null) {
                mBitmapDiskLruCache.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

好了,DiskLruCache的原理就讲完了!接下来给个demo,该demo是同时缓存了图片和文本,然后在断网情况下打开数据正常显示,我们来看看效果:

好了,贴下主要代码:

public class MainActivity extends ActionBarActivity {
    private ImageView mImageView;
    private TextView mTextView;
    private String url = "http://img.my.csdn.net/uploads/201507/21/1437459521_5133.jpg";
    private DiskLruCache mBitmapDiskLruCache ;
    private DiskLruCache mTextDiskLruCache;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView = (ImageView) findViewById(R.id.imageView);
        mTextView = (TextView) findViewById(R.id.textView);
        initBitmapDiskLruCache();
        initTextDiskLruCache();
        loadBitmap(url, mBitmapDiskLruCache,mTextDiskLruCache);
    }
    //初始化硬盘缓存,得到缓存对象
    public void initBitmapDiskLruCache() {
        File file = getDiskLruCacheDir(this, "bitmap");
        int versionID = getAppVersionNum(this);
        try {
            mBitmapDiskLruCache = DiskLruCache.open(file, versionID, 1, 10 * 1024 * 1024);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void initTextDiskLruCache() {
        File file = getDiskLruCacheDir(this, "text");
        int versionID = getAppVersionNum(this);
        try {
            mTextDiskLruCache = DiskLruCache.open(file, versionID, 1, 10 * 1024 * 1024);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 加载图片和文本数据,先判断硬盘缓存中有木有,有则从硬盘缓存中取出设置,没有则开启线程下载数据
     * @param url
     * @param mBitmapDiskLruCache
     * @param mTextDiskLruCache
     */
    public void loadBitmap(String url, DiskLruCache mBitmapDiskLruCache,DiskLruCache mTextDiskLruCache) {
        try {
            //从硬盘缓存中加载图片
            DiskLruCache.Snapshot snapshot = mBitmapDiskLruCache.get(String2MD5Tools.hashKeyForDisk(url));
            if (snapshot != null) {//如果硬盘缓存中存在该缓存文件
                InputStream inputStream = snapshot.getInputStream(0);
                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                if (bitmap != null) {
                    mImageView.setImageBitmap(bitmap);
                }
            }else{
                //硬盘缓存中不存在图片缓存则开启一个线程去下载图片
                DownloadTask task = new DownloadTask(mImageView, mTextView,mBitmapDiskLruCache,mTextDiskLruCache);
                task.execute(url);
            }

            DiskLruCache.Snapshot snapshot1 = mTextDiskLruCache.get(String2MD5Tools.hashKeyForDisk(url));
            if(snapshot1!=null){
                InputStream inputStream = snapshot1.getInputStream(0);
                if(inputStream!=null){
                    int len=-1;
                    byte[] by = new byte[1024];
                    StringBuilder builder = new StringBuilder();
                    while ((len=inputStream.read(by))!=-1){
                        builder.append(new String(by,0,len));
                    }
                    mTextView.setText(builder.toString());
                }
            }else{
                //硬盘缓存中不存在文本缓存则开启一个线程去下载
                DownloadTask task = new DownloadTask(mImageView, mTextView,mBitmapDiskLruCache,mTextDiskLruCache);
                task.execute(url);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * @param context
     * @return - 得到应用的版本号
     */
    private int getAppVersionNum(Context context) {
        try {
            PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
            return info.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return 1;
    }

    /**
     * @param cacheDirName - 缓存的最终目录文件夹名称
     * @return - 获取硬盘缓存的目录
     */
    private File getDiskLruCacheDir(Context context, String cacheDirName) {
        String cachePath;
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
                || !Environment.isExternalStorageRemovable()) {
            cachePath = context.getExternalCacheDir().getPath();
        } else {
            cachePath = context.getCacheDir().getPath();
        }
        File file = new File(cachePath + "/" + cacheDirName);
        if (!file.exists()) {
            file.mkdirs();
        }
        return file;
    }

    @Override
    protected void onPause() {
        super.onPause();
        try {
            if (mBitmapDiskLruCache != null) {
                mBitmapDiskLruCache.flush();
            }
            if(mTextDiskLruCache!=null){
                mTextDiskLruCache.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        try {
            if (mBitmapDiskLruCache != null) {
                mBitmapDiskLruCache.close();
            }
            if(mTextDiskLruCache!=null){
                mTextDiskLruCache.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

异步下载类:

public class DownloadTask extends AsyncTask<String, Void, Bitmap> {
    private ImageView imageView;
    private TextView mTextView;
    private String url;
    private DiskLruCache mBitmapDiskLruCache;
    private DiskLruCache mTextDiskLruCache;
    public DownloadTask(ImageView imageView,TextView mTextView, DiskLruCache mBitmapDiskLruCache,DiskLruCache mTextDiskLruCache) {
        this.imageView = imageView;
        this.mTextView = mTextView;
        this.mBitmapDiskLruCache = mBitmapDiskLruCache;
        this.mTextDiskLruCache = mTextDiskLruCache;
    }

    @Override
    protected Bitmap doInBackground(String... params) {
        url = params[0];
        Bitmap bitmap=null;
        boolean flag = false;
        try {
            //将下载的图片写入硬盘缓存中,bitmap目录下
            DiskLruCache.Editor editor = mBitmapDiskLruCache.edit(String2MD5Tools.hashKeyForDisk(url));
            if (editor != null) {
                OutputStream outputStream = editor.newOutputStream(0);
                flag = downloadBitmap(url,outputStream);
                if(flag){
                    editor.commit();//提交表示写入缓存成功
                }else{
                    editor.abort();//表示放弃此次写入
                }
            }
            //从硬盘缓存中获取图片
           DiskLruCache.Snapshot snapshot =  mBitmapDiskLruCache.get(String2MD5Tools.hashKeyForDisk(url));
            if(snapshot!=null){
                InputStream inputStream = snapshot.getInputStream(0);
                if(inputStream!=null){
                    bitmap = BitmapFactory.decodeStream(inputStream);//
                }
            }

            //将图片的文本数据写入硬盘缓存,text目录下
            DiskLruCache.Editor editor1 = mTextDiskLruCache.edit(String2MD5Tools.hashKeyForDisk(url));
            if(editor1!=null){
                OutputStream outputStream = editor1.newOutputStream(0);
                if(bitmap!=null){
                    outputStream.write(("height=" + bitmap.getHeight() + ",width=" + bitmap.getWidth()).toString().getBytes());
                    editor1.commit();
                }else{
                    editor1.abort();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    return bitmap;
}

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        super.onPostExecute(bitmap);
        if(imageView!=null&&bitmap!=null){
            imageView.setImageBitmap(bitmap);
        }
        if(mTextView!=null&&bitmap!=null){
            mTextView.setText(("height="+bitmap.getHeight()+",width="+bitmap.getWidth()).toString());
        }
    }
    /**
     * 从网络上下载图片
     * @param urlStr
     * @return
     */
    private boolean downloadBitmap(String urlStr,OutputStream outputStream) {
        HttpURLConnection connection = null;
        Bitmap bitmap = null;
        BufferedOutputStream bos;
        try {
            URL url = new URL(urlStr);
            connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(5000);
            connection.setReadTimeout(5000);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.connect();
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                InputStream mInputStream = connection.getInputStream();
                bos = new BufferedOutputStream(outputStream);
                int len=-1;
                byte[] by = new byte[1024];
                while((len=mInputStream.read(by))!=-1){
                    bos.write(by,0,len);
                    bos.flush();
                }
                mInputStream.close();
                return true;
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
        return false;
    }
}

源码地址:点击下载DiskLruCacheDemo

下次用LruCache+DiskLruCache结合给出个缓存加载大数量图片的demo!

版权声明:本文为博主原创文章,未经博主允许不得转载。转载注明出处:http://blog.csdn.net/u010687392

时间: 2024-10-07 12:01:13

DiskLruCache硬盘缓存技术详解的相关文章

ThinkPHP 缓存技术详解 使用大S方法

如果没有缓存的网站是百万级或者千万级的访问量,会给数据库或者服务器造成很大的压力,通过缓存,大幅减少服务器和数据库的负荷,假如我们把读取数据的过程分为三个层,第一个是访问层,第一个是缓存层,第三个是数据库存取层,如果没有缓存层,访问层是直接从数据库存取层读取数据,而设置缓存后,访问层不再是直接在数据库存取层读取,而是从缓存层读取数据. 我们做个简单的对比,假设一个页面,在一个小时可被访问100万次,如果这个页面每次被访问的时候,都直接读取数据库后再编译生成,在一个小时内将会重复性的生成100万次

php 面试必备:各种缓存技术详解

这门课程以电商网站为例,通过具体场景模块实战,让你更系统的掌握缓存原理.使用场景等相关知识,帮助你构建完整的缓存知识体系,胜任实际开发中缓存的处理,提升代码性能!    从原理到场景 系统讲解PHP缓存技术,PHP缓存视频教程包括文件缓存.内存数据库之Memcached.内存数据库之Redis.浏览器缓存和应用程序缓存    PHP精品缓存实战视频教程,PHP面试必考题目:缓存机制,PHP从底层研究缓存到实战缓存视频教程带源码. 原文地址:https://www.cnblogs.com/lxwp

Zookeeper技术:分布式架构详解、分布式技术详解、分布式事务

一.分布式架构详解 1.分布式发展历程 1.1 单点集中式 特点:App.DB.FileServer都部署在一台机器上.并且访问请求量较少 1.2? 应用服务和数据服务拆分 ?特点:App.DB.FileServer分别部署在独立服务器上.并且访问请求量较少 1.3? 使用缓存改善性能 ?特点:数据库中频繁访问的数据存储在缓存服务器中,减少数据库的访问次数,降低数据库的压力 1.4 应用服务器集群 ?特点:多台应用服务器通过负载均衡同时对外提供服务,解决单台服务器处理能力上限的问题 1.5 数据

实现高性能纠删码引擎 | 纠删码技术详解(下)

作者介绍: 徐祥曦,七牛云工程师,独立开发了多套高性能纠删码/再生码编码引擎.柳青,华中科技大学博士,研究方向为基于纠删码的分布式存储系统. 前言: 在上篇<如何选择纠删码编码引擎>中,我们简单了解了 Reed-Solomon Codes(RS 码)的编/解码过程,以及编码引擎的评判标准.但并没有就具体实现进行展开,本篇作为<纠删码技术详解>的下篇,我们将主要探讨工程实现的问题. 这里先简单提炼一下实现高性能纠删码引擎的要点:首先,根据编码理论将矩阵以及有限域的运算工程化,接下来主

Linux磁盘阵列技术详解(二)--raid 1创建

我在Linux磁盘阵列技术详解(一)里已经详细介绍了几种RAID磁盘阵列方式,原理以及创建raid 0 的详细步骤.那么这篇文档就着重讲解如何创建raid 1的技术: 步骤如下: ① 分区 同样我们还是以一块硬盘的不同分区为例,实际工作中应该是不同的硬盘才对. 具体分区步骤不再赘述! 分区后结果如下图所示: ② 创建raid 1 mdadm -C -v /dev/md1 -l 1 -n 2 -x 1 /dev/sdc1 /dev/sdc2 /dev/sdc3 或者 mdadm -C -v /de

CDN技术详解及实现原理

CDN技术详解 一本好的入门书是带你进入陌生领域的明灯,<CDN技术详解>绝对是带你进入CDN行业的那盏最亮的明灯.因此,虽然只是纯粹的重点抄录,我也要把<CDN技术详解>的精华放上网.公诸同好. 第一章    引言    “第一公里”是指万维网流量向用户传送的第一个出口,是网站服务器接入互联网的链路所能提供的带宽.这个带宽决定了一个 网站能为用户提供的访问速度和并发访问量.如果业务繁忙,用户的访问数越多,拥塞越严重,网站会在最需要向用户提供服务时失去用户.(还有“中间一公里” 和

Android 开源框架Universal-Image-Loader完全解析(二)--- 图片缓存策略详解

本篇文章继续为大家介绍Universal-Image-Loader这个开源的图片加载框架,介绍的是图片缓存策略方面的,如果大家对这个开源框架的使用还不了解,大家可以看看我之前写的一篇文章Android 开源框架Universal-Image-Loader完全解析(一)--- 基本介绍及使用,我们一般去加载大量的图片的时候,都会做缓存策略,缓存又分为内存缓存和硬盘缓存,我之前也写了几篇异步加载大量图片的文章,使用的内存缓存是LruCache这个类,LRU是Least Recently Used 近

J2EE学习篇之--JQuery技术详解

前面我们讲解了的J2EE的技术都是服务端的技术,下面我们来看一下前端的一些开发技术,这一篇我们来看一下jQuery技术 简介: jQuery由美国人John Resig创建,至今已吸引了来自世界各地的众多 javascript高手加入其team. jQuery是继prototype之后又一个优秀的Javascript框架.其宗旨是--WRITE LESS,DO MORE,写更少的代码,做更多的事情. 它是轻量级的js库(压缩后只有21k) ,这是其它的js库所不及的,它兼容CSS3,还兼容各种浏

hadoop应用开发技术详解

<大 数据技术丛书:Hadoop应用开发技术详解>共12章.第1-2章详细地介绍了Hadoop的生态系统.关键技术以及安装和配置:第3章是 MapReduce的使用入门,让读者了解整个开发过程:第4-5章详细讲解了分布式文件系统HDFS和Hadoop的文件I/O:第6章分析了 MapReduce的工作原理:第7章讲解了如何利用Eclipse来编译Hadoop的源代码,以及如何对Hadoop应用进行测试和调试:第8-9章 细致地讲解了MapReduce的开发方法和高级应用:第10-12章系统地讲