廢話不多述仍稀,首先來說明下 為什么要用圖片加載器 呢低剔,就是為了避免圖片重復(fù)從網(wǎng)絡(luò)加載账蓉。也就是在第一次從網(wǎng)絡(luò)加載之后就把圖片緩存在本地袱蚓,下次用的時候直接從本地查找钞啸,有的話就直接用,沒有再從網(wǎng)絡(luò)加載喇潘。
加載方式的話又有2種体斩,一種是加載在手機內(nèi)存中,另一種是緩存到SD卡中颖低。一般Android應(yīng)用的內(nèi)存很有限絮吵,所以用內(nèi)存緩存的話當應(yīng)用重啟時緩存在內(nèi)存中的就會丟失,但是緩存在內(nèi)存中比緩存在SD卡中讀取的時候更快忱屑,而且緩存在SD卡中需要手動釋放內(nèi)存蹬敲,不然就變成了垃圾內(nèi)存。
接下來分別講下內(nèi)存緩存和SD卡緩存莺戒,先定義一個接口規(guī)定2種緩存方式都需要完成的工作伴嗡,put(加入到緩存當中)和get(從緩存中獲取):
public interface ImageCache {
//用url來唯一標識bitmap
public void put(String url, Bitmap bitmap);
public Bitmap get(String url);
}
緩存到內(nèi)存的代碼:
public class MemoryCache implements ImageCache{
//用來緩存的工具類對象从铲,通過類聲明可以看出這個類也是通過key-value來存儲對象的
private LruCache<String, Bitmap> mImageCache;
public MemoryCache(){
initImageCache();
}
private void initImageCache() {
//計算當前應(yīng)用可使用內(nèi)存
final int maxMemory = (int)(Runtime.getRuntime().maxMemory() / 1024);
//分配作為緩存的內(nèi)存大小瘪校,官方推薦為當前應(yīng)用可使用內(nèi)存的1/8
final int cacheSize = maxMemory / 4;
//初始化緩存類
mImageCache = new LruCache<String, Bitmap>(cacheSize){
/*sizeof()方法。這個方法默認返回的是你緩存的item數(shù)目食店,如果你想要自定義size的大小渣淤,直接重寫這個方法赏寇,返回自定義的值即可*/
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes() * bitmap.getHeight() / 1024; } };
}
//將資源加入內(nèi)存緩存
@Override
public void put(String url, Bitmap bitmap){
mImageCache.put(url, bitmap);
}
//從內(nèi)存緩存通過url標識來獲取資源
@Override
public Bitmap get(String url){
return mImageCache.get(url);
}
}
緩存到SD卡的代碼如下:
public class DiskCache implements ImageCache {
//緩存路徑
static String cacheDir = "sdcard/cache/";
@Override
public Bitmap get(String url){
return BitmapFactory.decodeFile(cacheDir + url);
}
@Override
void put(String url, Bitmap bmp){
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(cacheDir + url);
bmp.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
} catch (Exception e){
e.printStackTrace();
} finally {
if (fileOutputStream != null){
try {
fileOutputStream.close();
} catch (IOException e){
e.printStackTrace();
}
}
}
}
}
那到底什么時候用什么緩存方式呢吉嫩?
我們可以在從網(wǎng)絡(luò)加載圖片的時候同時緩存在內(nèi)存和SD卡中价认,當需要使用圖片資源的時候就先從內(nèi)存查找,沒有的話再從SD卡中查找自娩,也沒有就從網(wǎng)絡(luò)加載再緩存到本地(同時緩存到內(nèi)存和SD卡)用踩。貼上代碼:
public class DoubleCache implements ImageCache{
MemoryCache mMemoryCache = new MemoryCache();
DiskCache mDiskCache = new DiskCache();
@Override
public Bitmap get(String url){
Bitmap bitmap = mMemoryCache.get(url);
if (bitmap == null){
bitmap = mDiskCache.get(url);
return bitmap;
}
@Override
public void put(String url, Bitmap bmp){
mMemoryCache.put(url, bmp);
mDiskCache.put(url, bmp);
}
}
到這里緩存部分邏輯就寫的差不多了,下面看看具體實現(xiàn)類面代碼:
public class ImageLoader {
//內(nèi)存緩存
ImageCache mImageCache = new DoubleCache();
//線程池忙迁,線程的數(shù)量為CPU數(shù)脐彩,可以同時處理多個緩存線程
//Runtime.getRuntime().availableProcessors() 得到的就是CPU數(shù)
ExecutorService mExecutorService = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors());
public void displayImage(final String url, final ImageView imageView){
Bitmap bitmap = mImageCache.get(url) ;
if (bitmap != null){
imageView.setImageBitmap(bitmap); return;
}
//圖片還未緩存,開啟線程從網(wǎng)上下載
submitLoadRequest(url, imageView);
}
private void submitLoadRequest(final String imageUrl, final ImageView imageView){
//需要開啟新線程姊扔,用url唯一標識
imageView imageView.setTag(imageUrl);
mExecutorService.submit(new Runnable() {
@Override
public void run() {
Bitmap bitmap = downloadImage(imageUrl);
if (bitmap == null){
return;
}
if (imageView.getTag().equals(imageUrl)){
imageView.setImageBitmap(bitmap);
}
mImageCache.put(imageUrl, bitmap);
}});
}
private Bitmap downloadImage(String imageUrl) {
Bitmap bitmap = null;
try {
URL url = new URL(imageUrl);
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
bitmap = BitmapFactory.decodeStream(conn.getInputStream());
conn.disconnect();
} catch (Exception e){
e.printStackTrace();
}
return bitmap;
}
}
到這里這個簡單的ImageLoader類就寫好了惠奸。這就是一個很簡單實用的工具類,網(wǎng)上比較完善的ImageLoader多得是恰梢,我寫這篇博客主要是整理一下思路也是分享一下自己的學(xué)習(xí)成果佛南。當然作為一個學(xué)生,我寫的文章肯定存在一些問題或者思考欠缺的地方嵌言,也希望大家能指出我的錯誤或不足嗅回。