Android下的图片缓存简单实现(避免软引用缓存)

来源:互联网 发布:淘宝运营公司那家强 编辑:程序博客网 时间:2024/06/05 19:17

在工作中,经常会遇到这样的情况,安卓客户端从服务器上获取图片并进行显示,但很多网络请求并不是理想的,事实上,网络请求时很耗时的,所以需要我们把图片保存到本地,等到服务器上的资源加载上以后,在显示出来,这样就会给用户一种比较流畅的感觉。


本类中通过两种方式来实现图片的缓存


  1. 通过Soft References来缓存图片(API不建议使用此类缓存图片)
  2. 将图片保存到本地磁盘缓存图片

缓存的逻辑如下:



  • 先把图片等资源保存到本地
  • 获取服务器图片
  • 将服务器图片等资源显示到客户端上
  • 在将新的图片等资源保存到本地

package com.loopj.image;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.lang.ref.SoftReference;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Bitmap.CompressFormat;import android.graphics.BitmapFactory;public class WebImageCache {    private static final String DISK_CACHE_PATH = "/web_image_cache/";    private ConcurrentHashMap<String, SoftReference<Bitmap>> memoryCache;    private String diskCachePath;    private boolean diskCacheEnabled = false;    private ExecutorService writeThread;    public WebImageCache(Context context) {        // Set up in-memory cache store        memoryCache = new ConcurrentHashMap<String, SoftReference<Bitmap>>();        // Set up disk cache store        Context appContext = context.getApplicationContext();        diskCachePath = appContext.getCacheDir().getAbsolutePath() + DISK_CACHE_PATH;        File outFile = new File(diskCachePath);        outFile.mkdirs();        diskCacheEnabled = outFile.exists();        // Set up threadpool for image fetching tasks        writeThread = Executors.newSingleThreadExecutor();    }    public Bitmap get(final String url) {        Bitmap bitmap = null;        // Check for image in memory        bitmap = getBitmapFromMemory(url);        // Check for image on disk cache        if(bitmap == null) {            bitmap = getBitmapFromDisk(url);            // Write bitmap back into memory cache            if(bitmap != null) {                cacheBitmapToMemory(url, bitmap);            }        }        return bitmap;    }    public void put(String url, Bitmap bitmap) {        cacheBitmapToMemory(url, bitmap);        cacheBitmapToDisk(url, bitmap);    }    public void remove(String url) {        if(url == null){            return;        }        // Remove from memory cache        memoryCache.remove(getCacheKey(url));        // Remove from file cache        File f = new File(diskCachePath, getCacheKey(url));        if(f.exists() && f.isFile()) {            f.delete();        }    }    public void clear() {        // Remove everything from memory cache        memoryCache.clear();        // Remove everything from file cache        File cachedFileDir = new File(diskCachePath);        if(cachedFileDir.exists() && cachedFileDir.isDirectory()) {            File[] cachedFiles = cachedFileDir.listFiles();            for(File f : cachedFiles) {                if(f.exists() && f.isFile()) {                    f.delete();                }            }        }    }    private void cacheBitmapToMemory(final String url, final Bitmap bitmap) {        memoryCache.put(getCacheKey(url), new SoftReference<Bitmap>(bitmap));    }    private void cacheBitmapToDisk(final String url, final Bitmap bitmap) {        writeThread.execute(new Runnable() {            @Override            public void run() {                if(diskCacheEnabled) {                    BufferedOutputStream ostream = null;                    try {                        ostream = new BufferedOutputStream(new FileOutputStream(new File(diskCachePath, getCacheKey(url))), 2*1024);                        bitmap.compress(CompressFormat.PNG, 100, ostream);                    } catch (FileNotFoundException e) {                        e.printStackTrace();                    } finally {                        try {                            if(ostream != null) {                                ostream.flush();                                ostream.close();                            }                        } catch (IOException e) {}                    }                }            }        });    }    private Bitmap getBitmapFromMemory(String url) {        Bitmap bitmap = null;        SoftReference<Bitmap> softRef = memoryCache.get(getCacheKey(url));        if(softRef != null){            bitmap = softRef.get();        }        return bitmap;    }    private Bitmap getBitmapFromDisk(String url) {        Bitmap bitmap = null;        if(diskCacheEnabled){            String filePath = getFilePath(url);            File file = new File(filePath);            if(file.exists()) {                bitmap = BitmapFactory.decodeFile(filePath);            }        }        return bitmap;    }    private String getFilePath(String url) {        return diskCachePath + getCacheKey(url);    }    private String getCacheKey(String url) {        if(url == null){            throw new RuntimeException("Null url passed in");        } else {            return url.replaceAll("[.:/,%?&=]", "+").replaceAll("[+]+", "+");        }    }}

本类用到了图片的软引用技术,加载图片时

  • 先从软引用里面加载图片;
  • 如果软引用里面没有图片,在从内存中加载图片

软引用(SoftReference)

看看API是如何解释的:


/* A reference that is cleared when its referent is not strongly
reachable and * there is memory pressure. * *

Avoid Soft
References for Caching

* In practice, soft references are
inefficient for caching. The runtime doesn’t * have enough
information on which references to clear and which to keep. Most *
fatally, it doesn’t know what to do when given the choice between
clearing a * soft reference and growing the heap. * *

The lack
of information on the value to your application of each reference *
limits the usefulness of soft references. References that are cleared
too * early cause unnecessary work; those that are cleared too late
waste memory. * *

Most applications should use an {@code
android.util.LruCache} instead of * soft references. LruCache has an
effective eviction policy and lets the user * tune how much memory is
allotted.


上面这段话的大概意思就是说不建议使用软引用进行缓存,软引用是inefficient的。因为不知道什么时候就被垃圾回收器回收了。

建议使用android.util.LruCache(强引用)来进行缓存。 以后在讲讲软引用,强引用。

1 0