Android自定義簡單的圖片加載器

廢話不多述,首先來說明下 為什么要用圖片加載器 呢,就是為了避免圖片重復從網絡加載。也就是在第一次從網絡加載之后就把圖片緩存在本地,下次用的時候直接從本地查找,有的話就直接用,沒有再從網絡加載。

加載方式的話又有2種,一種是加載在手機內存中,另一種是緩存到SD卡中。一般Android應用的內存很有限,所以用內存緩存的話當應用重啟時緩存在內存中的就會丟失,但是緩存在內存中比緩存在SD卡中讀取的時候更快,而且緩存在SD卡中需要手動釋放內存,不然就變成了垃圾內存。

接下來分別講下內存緩存和SD卡緩存,先定義一個接口規定2種緩存方式都需要完成的工作,put(加入到緩存當中)和get(從緩存中獲取):

public interface ImageCache {
    //用url來唯一標識bitmap
    public void put(String url, Bitmap bitmap);
    public Bitmap get(String url);
}

緩存到內存的代碼:

public class MemoryCache implements ImageCache{
    //用來緩存的工具類對象,通過類聲明可以看出這個類也是通過key-value來存儲對象的
    private LruCache<String, Bitmap> mImageCache;

    public MemoryCache(){
        initImageCache(); 
    }

    private void initImageCache() {
    //計算當前應用可使用內存
    final int maxMemory = (int)(Runtime.getRuntime().maxMemory() / 1024);

    //分配作為緩存的內存大小,官方推薦為當前應用可使用內存的1/8
    final int cacheSize = maxMemory / 4;

    //初始化緩存類
    mImageCache = new LruCache<String, Bitmap>(cacheSize){

    /*sizeof()方法。這個方法默認返回的是你緩存的item數目,如果你想要自定義size的大小,直接重寫這個方法,返回自定義的值即可*/
    @Override
    protected int sizeOf(String key, Bitmap bitmap) {
        return bitmap.getRowBytes() * bitmap.getHeight() / 1024; } };
    }

    //將資源加入內存緩存
    @Override
    public void put(String url, Bitmap bitmap){
        mImageCache.put(url, bitmap);
    }

    //從內存緩存通過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();
                }
            }
        }
    }
}

那到底什么時候用什么緩存方式呢?

我們可以在從網絡加載圖片的時候同時緩存在內存和SD卡中,當需要使用圖片資源的時候就先從內存查找,沒有的話再從SD卡中查找,也沒有就從網絡加載再緩存到本地(同時緩存到內存和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);
    }
}

到這里緩存部分邏輯就寫的差不多了,下面看看具體實現類面代碼:

public class ImageLoader {

    //內存緩存
    ImageCache mImageCache = new DoubleCache();

    //線程池,線程的數量為CPU數,可以同時處理多個緩存線程
    //Runtime.getRuntime().availableProcessors() 得到的就是CPU數
    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;
        }
        //圖片還未緩存,開啟線程從網上下載
        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類就寫好了。這就是一個很簡單實用的工具類,網上比較完善的ImageLoader多得是,我寫這篇博客主要是整理一下思路也是分享一下自己的學習成果。當然作為一個學生,我寫的文章肯定存在一些問題或者思考欠缺的地方,也希望大家能指出我的錯誤或不足。

 

來自:http://www.jianshu.com/p/6b35a813ef48

 

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