Android網絡圖片緩存

xg48 9年前發布 | 3K 次閱讀 Java Android

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


//內存緩存

public class ImageMemoryCache {

/**

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

*/

privatestatic finalint SOFT_CACHE_SIZE = 15;// 軟引用緩存容量

privatestatic LruCache<String, Bitmap> mLruCache; // 硬引用緩存

privatestatic LinkedHashMap<String, SoftReference<Bitmap>>mSoftCache; // 軟引用緩存

public ImageMemoryCache(Context context) {

int memClass = ((ActivityManager) context

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

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

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

@Override

protectedint sizeOf(String key, Bitmap value) {

if (value !=null)

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

else

return 0;

}

@Override

protectedvoid 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) {

privatestatic final long serialVersionUID = 6040103833179403725L;

@Override

protectedboolean removeEldestEntry(

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

if (size() >SOFT_CACHE_SIZE) {

returntrue;

}

returnfalse;

}

};

}

/**

  • 從緩存中獲取圖片

*/

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);

}

}

}

returnnull;

}

/**

  • 添加圖片到緩存

*/

publicvoid addBitmapToCache(String url, Bitmap bitmap) {

if (bitmap !=null) {

synchronized (mLruCache) {

mLruCache.put(url, bitmap);

}

}

}

publicvoid 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 finalint CACHE_SIZE = 10;

privatestaticfinalintFREE_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; </pre>

 本文由用戶 xg48 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!