【從零開始寫一個簡單的ImageLoader框架】ImageLoader分析

許佳佳233發表於2016-08-12

#相關文章
【從零開始寫一個簡單的ImageLoader框架】專案介紹

【從零開始寫一個簡單的ImageLoader框架】ImageLoader分析

【從零開始寫一個簡單的ImageLoader框架】MyImageLoader程式碼簡介

#專案涉及知識點
##1、網路獲取
##2、圖片壓縮
##3、記憶體快取
##4、磁碟快取
##5、執行緒池
##6、Handler
##7、RecyclerView(demo中使用)

#ImageLoader獲取圖片一般流程
1、從記憶體快取中檢視是否有該圖片,如果有就設定到imageView上。

2、如果沒有記憶體快取,就從磁碟快取中檢視是否有該圖片,如果有就設定到imageView上,並且把該圖片設定到記憶體快取中。

3、如果既沒有記憶體快取也沒有磁碟快取,那麼就直接從網路獲取該圖片,並使用磁碟快取,然後從磁碟中讀取該圖片。將圖片根據ImageView的寬高壓縮後進行顯示。

4、由於獲取記憶體快取較快,所以不需要使用執行緒。
磁碟快取由於存在從網路下載圖片這一較為耗時的環節,所以要使用執行緒。
考慮到可能會有多個圖片同時顯示,所以就要使用執行緒池進行統一管理。

5、線上程中無法直接更新UI,所以也要使用到Handler

#從程式碼瞭解流程(建議結合原始碼看)
##程式碼預覽
這裡寫圖片描述

在筆者demo中主要使用到的方法為bindBitMap,此方法使用與ImageRecyclerAdapter中

public void setData(String url) {
            //垂直線性佈局
            //載入高清圖片並按寬高壓縮
            //MyUtils.Log(url);
            MyImageLoader.getInstance(context).bindBitmap(url, imageView, width, height);

        }

我們直接跳轉到bindBitmap中看邏輯:

public void bindBitmap(final String uri, final ImageView imageView, final int reqWidth, final int reqHeight) {
        //設定載入loadding圖片
        imageView.setImageResource(R.drawable.ic_loading);

        //從記憶體快取中獲取bitmap
        Bitmap bitmap = imageLrucache.loadBitmapFromMemCache(uri);
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
            return;
        }
        //磁碟快取包含在LoadBitmapTask中
        LoadBitmapTask loadBitmapTask = new LoadBitmapTask(mContext, imageView, uri, reqWidth, reqHeight);
        //使用執行緒池去執行Runnable物件
        THREAD_POOL_EXECUTOR.execute(loadBitmapTask);

    }

可以看到,如果記憶體快取讀到了bitmap,那麼就會直接顯示並且退出,如果沒有,那麼就會執行LoadBitmapTask,LoadBitmapTask是一個Runnable物件,使用執行緒池呼叫時,它的邏輯會是線上程中進行的,我們可以繼續看一下里面的邏輯。

 @Override
    public void run() {
        //從磁碟或者網路獲取bitmap
        final Bitmap bitmap = loadBitmap(uri, reqWidth, reqHeight);

        //使用handler更新UI
        TaskResult loaderResult = new TaskResult(imageView, bitmap);
        imageHandler.obtainMessage(MESSAGE_POST_RESULT, loaderResult).sendToTarget();

        if (callback != null) {
            Handler handler = new Handler(Looper.getMainLooper());
            handler.post(new Runnable() {
                @Override
                public void run() {
                    callback.onResponse(bitmap);
                }
            });

        }
    }

我們發現loadBitmap(uri, reqWidth, reqHeight)在之後,就直接使用Handler進行UI的操作了,那麼執行緒邏輯必然在這個裡面。

 private Bitmap loadBitmap(String uri, int reqWidth, int reqHeight) {
        Bitmap bitmap = null;
        try {
            //從磁碟快取中獲取bitmap
            bitmap = MyImageLoader.getImageDiskLruCache(mContext).loadBitmapFromDiskCache(uri, reqWidth, reqHeight);
            if (bitmap != null) {
                MyUtils.Log("從磁碟快取中獲取到了bitmap");
                //新增到記憶體快取中
                MyImageLoader.getImageLruCache().put(MD5Utils.hashKeyFromUrl(uri), bitmap);
                return bitmap;
            } else {
                //從網路下載bitmap到磁碟快取,並從磁碟快取中獲取bitmap
                bitmap = loadBitmapFromHttp(uri, reqWidth, reqHeight);
                if (bitmap != null) {
                    MyUtils.Log("從網路下載並儲存到磁碟並從中讀取bitmap成功");
                }

            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        if (bitmap == null && !mIsDiskLruCacheCreated) {
            //如果sd卡已滿,無法使用磁碟快取,則通過網路下載bitmap,一般不會呼叫這一步
            bitmap = NetWork.downloadBitmapFromUrl(uri);
            MyUtils.Log("sd卡滿了,直接從網路獲取");
        }
        return bitmap;
    }

如上,我們就找到了磁碟快取的程式碼了:從磁碟快取中如果找到了圖片,就會將圖片新增到記憶體快取中並返回bitmap,如果沒有找到,就會從網上進行下載。

#知識點詳述連結
以下知識點於《Android開發藝術探索》中均有闡述。
##1、圖片壓縮
此文章來自 中文版的Android Training。
http://hukai.me/android-training-course-in-chinese/graphics/displaying-bitmaps/load-bitmap.html

##2、記憶體快取
此文章來自 中文版的Android Training。
http://hukai.me/android-training-course-in-chinese/graphics/displaying-bitmaps/cache-bitmap.html
##3、磁碟快取
Android DiskLruCache完全解析,硬碟快取的最佳方案
此文章為郭霖前輩所著。
http://blog.csdn.net/guolin_blog/article/details/28863651
##4、執行緒池
此文章來自 中文版的Android Training。
http://hukai.me/android-training-course-in-chinese/performance/multi-threads/create-threadpool.html
##5、Handler
Handler類和Handler,Loop,MessageQueue的工作原理
http://blog.csdn.net/double2hao/article/details/50991441
##7、RecyclerView(demo中使用)
android RecyclerView佈局真的只是那麼簡單!(筆者原創)
http://blog.csdn.net/double2hao/article/details/51177594

#專案下載地址

http://download.csdn.net/detail/double2hao/9601732

相關文章