从零开始编写图片加载库(五)之图片缓存DiskCache

来源:互联网 发布:淘宝类目007是什么牌子 编辑:程序博客网 时间:2024/05/01 15:29

1.写在前面

在处理图片比较多的应用中,为了提高程序的响应速率,不可避免的需要硬盘缓存技术和内存缓存技术结合使用,根据图片地址去请求网络的时候,先请求内存,如果内存没有再去请求本地缓存,如果本地缓存 没有再请求网络。这是一般图片加载框架的处理思路。

2.DiskLruCache的介绍

DiskLruCache是什么?DiskLruCache是一款优秀的第三方硬盘缓存解决方案,我们熟知的网易新闻就是通过这个来缓存图片到本地。


网易新闻


网易新闻需要加载的图片还是挺多的,如果每次进入app都需要请求网络加载图片显然是不合适的,一方面流量的消耗还有就是性能影响,那么保存到本地是一个很好的解决方案。那么网易是怎么保存到本地的呢?


缓存目录


DiskLruCache的缓存目录是可以自己定义的,但是一般我们都将缓存文件保存在 /sdcard/Android/data//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);    }

2.1DiskLruCache的使用

前面絮叨半天,进入正题吧,DiskLruCache的使用也是比较简单,提供了友好的访问接口。

  1. 打开缓存
    获取DiskLruCache的方法
    /**     * Opens the cache in {@code directory}, creating a cache if none exists     * there.     *     * @param directory a writable directory     * @param valueCount the number of values per cache entry. Must be positive.     * @param maxSize the maximum number of bytes this cache should use to store     * @param maxFileCount the maximum file count this cache should store     * @throws IOException if reading or writing the cache directory fails     */ public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize, int maxFileCount)            throws IOException {        if (maxSize <= 0) {            throw new IllegalArgumentException("maxSize <= 0");        }        if (maxFileCount <= 0) {            throw new IllegalArgumentException("maxFileCount <= 0");        }        if (valueCount <= 0) {            throw new IllegalArgumentException("valueCount <= 0");        }        // If a bkp file exists, use it instead.        File backupFile = new File(directory, JOURNAL_FILE_BACKUP);        if (backupFile.exists()) {            File journalFile = new File(directory, JOURNAL_FILE);            // If journal file also exists just delete backup file.            if (journalFile.exists()) {                backupFile.delete();            } else {                renameTo(backupFile, journalFile, false);            }        }        // Prefer to pick up where we left off.        DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize, maxFileCount);        if (cache.journalFile.exists()) {            try {                cache.readJournal();                cache.processJournal();                cache.journalWriter = new BufferedWriter(                        new OutputStreamWriter(new FileOutputStream(cache.journalFile, true), Util.US_ASCII));                return cache;            } catch (IOException journalIsCorrupt) {                System.out                        .println("DiskLruCache "                                + directory                                + " is corrupt: "                                + journalIsCorrupt.getMessage()                                + ", removing");                cache.delete();            }        }        // Create a new empty cache.        directory.mkdirs();        cache = new DiskLruCache(directory, appVersion, valueCount, maxSize, maxFileCount);        cache.rebuildJournal();        return cache;    }
  1. 保存文件

    /** * 保存文件到硬盘 *  * @param key * @param imageStream * @return * @throws IOException */public boolean save(String key, InputStream imageStream) throws IOException {    DiskLruCache.Editor editor = cache.edit(key);    if (editor == null) {        return false;    }    OutputStream os = new BufferedOutputStream(editor.newOutputStream(0),            DEFAULT_BUFFER_SIZE);    int count;    byte[] bs = new byte[DEFAULT_BUFFER_SIZE];    while ((count = imageStream.read(bs, 0, DEFAULT_BUFFER_SIZE)) != -1) {        os.write(bs, 0, count);    }    os.flush();    editor.commit();    return true;}
  2. 获取文件

    /** * 根据key去获取文件存储目录 *  * @param key * @return */public File get(String key) {    DiskLruCache.Snapshot snapshot = null;    try {        snapshot = cache.get(key);        return snapshot == null ? null : snapshot.getFile(0);    } catch (IOException e) {        e.printStackTrace();        return null;    }}
  3. 删除文件
    /**     * 根据key去删除文件     * @param key     * @return     */    public boolean remove(String key) {        try {            return cache.remove(key);        } catch (IOException e) {            e.printStackTrace();            return false;        }    }

2.2.DiskLruCache的实际应用效果

为了演示DiskLruCache的效果,建了一个项目,通过网络下载图片,将获取的文件保存到本地,通过Handler获取更新UI通知,根据下载的图片的key去本地查找图片并且显示。

package cn.sundroid.loader;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.URL;import cn.sundroid.cache.ext.LruDiskCache;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Bundle;import android.os.Environment;import android.os.Handler;import android.util.Log;import android.widget.ImageView;public class MainActivity extends Activity {    private ImageView image;    private final String TAG = "ImageLoader";    private int cacheMaxSize = 10 * 1024 * 1024; //10M    LruDiskCache cache;    private final String IMAGE_CACHE_KEY = "image_cache_key";    private Handler handler = new Handler() {        public void handleMessage(android.os.Message msg) {            File file = cache.get(IMAGE_CACHE_KEY);            Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());            image.setImageBitmap(bitmap);        };    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        File cacheDir = getDiskCacheDir(getApplicationContext(), "imageloader");        if (!cacheDir.exists()) {            cacheDir.mkdirs();        }        try {            //硬盘初始化            cache = new LruDiskCache(cacheDir, cacheMaxSize, 0);        } catch (IOException e1) {            e1.printStackTrace();        }        image = (ImageView) findViewById(R.id.image);        //开启一个新线程        new Thread(new Runnable() {            @Override            public void run() {                try {                    // 网络连接                    HttpURLConnection connection = (HttpURLConnection) new URL(                            "http://img4.duitang.com/uploads/item/201111/25/20111125231822_MCxG5.thumb.600_0.jpg")                            .openConnection();                    connection.setConnectTimeout(3 * 1000);                    connection.setReadTimeout(20 * 1000);                    // 读取文件流                    InputStream is = connection.getInputStream();                    Log.e(TAG, "put InputStream into memory cache");                    cache.save(IMAGE_CACHE_KEY, is);                    // 发送一个消息给Handler用于更新消息                    handler.sendEmptyMessage(0x10);                } catch (MalformedURLException e) {                    e.printStackTrace();                } catch (IOException e) {                    e.printStackTrace();                }            }        }).start();    }    //获取缓存路径    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);    }}

效果


缓存


源代码下载==》

0 0
原创粉丝点击