Android網絡圖片緩存

獲取一張圖片,從三個地方進行獲取,首先是內存緩存,而後是文件緩存,最後才從網絡中獲取。android

//內存緩存算法

public class ImageMemoryCache {緩存

/**網絡

* 從內存讀取數據速度是最快的,爲了更大限度使用內存,這裏使用了兩層緩存。 硬引用緩存不會輕易被回收,用來保存經常使用數據,不經常使用的轉入軟引用緩存。less

*/ide

private static final int SOFT_CACHE_SIZE = 15; // 軟引用緩存容量url

private static LruCache<String, Bitmap> mLruCache; // 硬引用緩存spa

private static LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache; // 軟引用緩存code


public ImageMemoryCache(Context context) {orm

int memClass = ((ActivityManager) context

.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();

int cacheSize = 1024 * 1024 * memClass / 4; // 硬引用緩存容量,爲系統可用內存的1/4

mLruCache = new LruCache<String, Bitmap>(cacheSize) {

@Override

protected int sizeOf(String key, Bitmap value) {

if (value != null)

return value.getRowBytes() * value.getHeight();

else

return 0;

}


@Override

protected void entryRemoved(boolean evicted, String key,

Bitmap oldValue, Bitmap newValue) {

if (oldValue != null)

// 硬引用緩存容量滿的時候,會根據LRU算法把最近沒有被使用的圖片轉入此軟引用緩存

mSoftCache.put(key, new SoftReference<Bitmap>(oldValue));

}

};

mSoftCache = new LinkedHashMap<String, SoftReference<Bitmap>>(

SOFT_CACHE_SIZE, 0.75f, true) {

private static final long serialVersionUID = 6040103833179403725L;


@Override

protected boolean removeEldestEntry(

Entry<String, SoftReference<Bitmap>> eldest) {

if (size() > SOFT_CACHE_SIZE) {

return true;

}

return false;

}

};

}


/**

* 從緩存中獲取圖片

*/

public Bitmap getBitmapFromCache(String url) {

Bitmap bitmap;

// 先從硬引用緩存中獲取

synchronized (mLruCache) {

bitmap = mLruCache.get(url);

if (bitmap != null) {

// 若是找到的話,把元素移到LinkedHashMap的最前面,從而保證在LRU算法中是最後被刪除

mLruCache.remove(url);

mLruCache.put(url, bitmap);

return bitmap;

}

}

// 若是硬引用緩存中找不到,到軟引用緩存中找

synchronized (mSoftCache) {

SoftReference<Bitmap> bitmapReference = mSoftCache.get(url);

if (bitmapReference != null) {

bitmap = bitmapReference.get();

if (bitmap != null) {

// 將圖片移回硬緩存

mLruCache.put(url, bitmap);

mSoftCache.remove(url);

return bitmap;

} else {

mSoftCache.remove(url);

}

}

}

return null;

}


/**

* 添加圖片到緩存

*/

public void addBitmapToCache(String url, Bitmap bitmap) {

if (bitmap != null) {

synchronized (mLruCache) {

mLruCache.put(url, bitmap);

}

}

}


public void clearCache() {

mSoftCache.clear();

}

}



//文件緩存,緩存到SD卡上

public class ImageFileCache {

private static final String CACHDIR = "ImgCach";

private static final String WHOLESALE_CONV = ".cach";

private static final int MB = 1024*1024;

   private static final int CACHE_SIZE = 10;

   private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 10;

public ImageFileCache() {

//清理文件緩存

removeCache(getDirectory());

}

   /** 從緩存中獲取圖片 **/

public Bitmap getImage(final String url) {

final String path = getDirectory() + "/" + convertUrlToFileName(url);

File file = new File(path);

if (file.exists()) {

Bitmap bmp = BitmapFactory.decodeFile(path);

if (bmp == null) {

file.delete();

} else {

updateFileTime(path);

return bmp;

}

}

return null;

}

   /** 將圖片存入文件緩存 **/

public void saveBitmap(Bitmap bm, String url) {

if (bm == null) {

return;

}

       //判斷sdcard上的空間

if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {

//SD空間不足

return;

}

String filename = convertUrlToFileName(url);

String dir = getDirectory();

File dirFile = new File(dir);

if (!dirFile.exists())

dirFile.mkdirs();

File file = new File(dir +"/" + filename);

try {

file.createNewFile();

OutputStream outStream = new FileOutputStream(file);

bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);

outStream.flush();

outStream.close();

} catch (FileNotFoundException e) {

           Log.w("ImageFileCache", "FileNotFoundException");

} catch (IOException e) {

           Log.w("ImageFileCache", "IOException");

}

}

/**

* 計算存儲目錄下的文件大小,

* 當文件總大小大於規定的CACHE_SIZE或者sdcard剩餘空間小於FREE_SD_SPACE_NEEDED_TO_CACHE的規定

* 那麼刪除40%最近沒有被使用的文件

*/

private boolean removeCache(String dirPath) {

File dir = new File(dirPath);

File[] files = dir.listFiles();

if (files == null) {

return true;

}

if (!android.os.Environment.getExternalStorageState().equals(

android.os.Environment.MEDIA_MOUNTED)) {

return false;

}

int dirSize = 0;

for (int i = 0; i < files.length; i++) {

if (files[i].getName().contains(WHOLESALE_CONV)) {

dirSize += files[i].length();

}

}

if (dirSize > CACHE_SIZE * MB || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {

int removeFactor = (int) ((0.4 * files.length) + 1);

Arrays.sort(files, new FileLastModifSort());

for (int i = 0; i < removeFactor; i++) {

if (files[i].getName().contains(WHOLESALE_CONV)) {

files[i].delete();

}

}

}

if (freeSpaceOnSd() <= CACHE_SIZE) {

return false;

}

return true;

}

   /** 修改文件的最後修改時間 **/

public void updateFileTime(String path) {

File file = new File(path);

long newModifiedTime = System.currentTimeMillis();

file.setLastModified(newModifiedTime);

}

   /** 計算sdcard上的剩餘空間 **/

private int freeSpaceOnSd() {

StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());

double sdFreeMB = ((double)stat.getAvailableBlocks() * (double) stat.getBlockSize()) / MB;

return (int) sdFreeMB;

}

   /** 將url轉成文件名 **/

private String convertUrlToFileName(String url) {

String[] strs = url.split("/");

return strs[strs.length - 1] + WHOLESALE_CONV;

}

   /** 得到緩存目錄 **/

private String getDirectory() {

String dir = getSDPath() + "/" + CACHDIR;

return dir;

}

   /** 取SD卡路徑 **/

private String getSDPath() {

File sdDir = null;

boolean sdCardExist = Environment.getExternalStorageState().equals(

android.os.Environment.MEDIA_MOUNTED);  //判斷sd卡是否存在

if (sdCardExist) {

sdDir = Environment.getExternalStorageDirectory();  //獲取根目錄

}

if (sdDir != null) {

return sdDir.toString();

} else {

return "";

}

}

/**

* 根據文件的最後修改時間進行排序

*/

private class FileLastModifSort implements Comparator<File> {

public int compare(File arg0, File arg1) {

if (arg0.lastModified() > arg1.lastModified()) {

return 1;

} else if (arg0.lastModified() == arg1.lastModified()) {

return 0;

} else {

return -1;

}

}

}

}



//從網絡加載圖片

public class ImageGetFromHttp {

private static final String LOG_TAG = "ImageGetFromHttp";

public static Bitmap downloadBitmap(String url) {

final HttpClient client = new DefaultHttpClient();

final HttpGet getRequest = new HttpGet(url);

try {

HttpResponse response = client.execute(getRequest);

final int statusCode = response.getStatusLine().getStatusCode();

if (statusCode != HttpStatus.SC_OK) {

Log.w(LOG_TAG, "Error " + statusCode + " while retrieving bitmap from " + url);

return null;

}

final HttpEntity entity = response.getEntity();

if (entity != null) {

InputStream inputStream = null;

try {

inputStream = entity.getContent();

FilterInputStream fit = new FlushedInputStream(inputStream);

return BitmapFactory.decodeStream(fit);

} finally {

if (inputStream != null) {

inputStream.close();

inputStream = null;

}

entity.consumeContent();

}

}

} catch (IOException e) {

getRequest.abort();

           Log.w(LOG_TAG, "I/O error while retrieving bitmap from " + url, e);

} catch (IllegalStateException e) {

getRequest.abort();

Log.w(LOG_TAG, "Incorrect URL: " + url);

} catch (Exception e) {

getRequest.abort();

           Log.w(LOG_TAG, "Error while retrieving bitmap from " + url, e);

} finally {

client.getConnectionManager().shutdown();

}

return null;

}

/*

* An InputStream that skips the exact number of bytes provided, unless it reaches EOF.

*/

static class FlushedInputStream extends FilterInputStream {

public FlushedInputStream(InputStream inputStream) {

super(inputStream);

}

       @Override

public long skip(long n) throws IOException {

long totalBytesSkipped = 0L;

while (totalBytesSkipped < n) {

long bytesSkipped = in.skip(n - totalBytesSkipped);

if (bytesSkipped == 0L) {

int b = read();

if (b < 0) {

break;  // we reached EOF

} else {

bytesSkipped = 1; // we read one byte

}

}

totalBytesSkipped += bytesSkipped;

}

return totalBytesSkipped;

}

}

}



//=============================獲取圖片========================================

/*** 得到一張圖片,從三個地方獲取,首先是內存緩存,而後是文件緩存,最後從網絡獲取 ***/

public Bitmap getBitmap(String url) {

// 從內存緩存中獲取圖片

Bitmap result = memoryCache.getBitmapFromCache(url);

if (result == null) {

// 文件緩存中獲取

result = fileCache.getImage(url);

if (result == null) {

// 從網絡獲取

result = ImageGetFromHttp.downloadBitmap(url);

if (result != null) {

fileCache.saveBitmap(result, url);

memoryCache.addBitmapToCache(url, result);

}

} else {

// 添加到內存緩存

memoryCache.addBitmapToCache(url, result);

}

}

return result;

}

相關文章
相關標籤/搜索