您的位置:首页 > 移动开发 > Android开发

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

2015-12-03 23:28 375 查看

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

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

通过Soft References来缓存图片(API不建议使用此类缓存图片)

将图片保存到本地磁盘缓存图片

缓存的逻辑如下:

先把图片等资源保存到本地

获取服务器图片

将服务器图片等资源显示到客户端上

在将新的图片等资源保存到本地

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(强引用)来进行缓存。 以后在讲讲软引用,强引用。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  图片缓存 软引用