教你寫Android ImageLoader架構之圖片載入與載入策略,

來源:互聯網
上載者:User

教你寫Android ImageLoader架構之圖片載入與載入策略,

在教你寫Android ImageLoader架構之初始配置與請求調度中,我們已經講述了ImageLoader的請求配置與調度相關的設計與實現。今天我們就來深入瞭解圖片的具體載入過程以及載入的策略(包括按順序載入和逆序載入) ,在這其中我會分享我的一些設計決策,也歡迎大家給我提建議。

圖片的載入Loader與LoaderManager的實現

在上一篇文章教你寫Android ImageLoader架構之初始配置與請求調度中,我們聊到了Loader與LoaderManager。 ImageLoader不斷地從隊列中擷取請求,然後解析到圖片uri的schema,從schema的格式就可以知道它是儲存在哪裡的圖片。例如網狀圖片對象的schema是http或者https,sd卡儲存的圖片對應的schema為file,schemae與Loader有一個對應關係。根據schema我們從LoaderManager中擷取對應的Loader來載入圖片。這個設計保證了SimpleImageLoader可載入圖片類型的可擴充性,這就是為什麼會增加loader這個包的原因。使用者只需要根據uri的格式來構造圖片uri,並且實現自己的Loader類,然後將Loader對象注入到LoaderManager即可。RequestDispatcher中的run函數如下 :

 @Override    public void run() {        try {            while (!this.isInterrupted()) {                final BitmapRequest request = mRequestQueue.take();                if (request.isCancel) {                    continue;                }                final String schema = parseSchema(request.imageUri);                // 根據schema擷取loader                Loader imageLoader = LoaderManager.getInstance().getLoader(schema);                imageLoader.loadImage(request);            }        } catch (InterruptedException e) {            Log.i("", "### 請求分發器退出");        }    }

Loader只定義了一個介面,只用一個載入圖片的方法。

public interface Loader {    public void loadImage(BitmapRequest result);}

抽象是為了可擴充,定義這個介面,我們就可以注入自己的圖片載入實作類別。例如從資源、assets中載入。不管從網路還是本地載入圖片,我們載入圖片的過程有如下幾個步驟:

我們可以發現,不管從哪裡載入圖片,這些邏輯都是通用的,因此我抽象了一個AbsLoader類。它將這幾個過程抽象起來,只將變化的部分交給子類處理,就相當於AbsLoader封裝了一個邏輯架構( 可以思考用了什麼設計模式),大致代碼如下 :

/** * @author mrsimple */public abstract class AbsLoader implements Loader {    /**     * 圖片緩衝     */    private static BitmapCache mCache = SimpleImageLoader.getInstance().getConfig().bitmapCache;    @Override    public final void loadImage(BitmapRequest request) {        // 1、從緩衝中擷取        Bitmap resultBitmap = mCache.get(request);        Log.e("", "### 是否有緩衝 : " + resultBitmap + ", uri = " + request.imageUri);        if (resultBitmap == null) {            showLoading(request);            // 2、沒有緩衝,調用onLoaderImage載入圖片            resultBitmap = onLoadImage(request);            // 3、緩衝圖片            cacheBitmap(request, resultBitmap);        } else {            request.justCacheInMem = true;        }        // 4、將結果投遞到UI線程        deliveryToUIThread(request, resultBitmap);    }    /** 載入圖片的hook方法,留給子類處理     * @param request     * @return     */    protected abstract Bitmap onLoadImage(BitmapRequest request);    // 代碼省略    }

代碼邏輯如上所述實現了一個模板函數,變化的部分就是onLoadImage,子類在這裡實現真正的載入圖片的方法。比如從網路上載入圖片。

/** * @author mrsimple */public class UrlLoader extends AbsLoader {    @Override    public Bitmap onLoadImage(BitmapRequest request) {        final String imageUrl = request.imageUri;        FileOutputStream fos = null;        InputStream is = null;        try {            URL url = new URL(imageUrl);            final HttpURLConnection conn = (HttpURLConnection) url.openConnection();            is = new BufferedInputStream(conn.getInputStream());            is.mark(is.available());            final InputStream inputStream = is;            BitmapDecoder bitmapDecoder = new BitmapDecoder() {                @Override                public Bitmap decodeBitmapWithOption(Options options) {                    Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);                    //                    if (options.inJustDecodeBounds) {                        try {                            inputStream.reset();                        } catch (IOException e) {                            e.printStackTrace();                        }                    } else {                        // 關閉流                        conn.disconnect();                    }                    return bitmap;                }            };            return bitmapDecoder.decodeBitmap(request.getImageViewWidth(),                    request.getImageViewHeight());        } catch (Exception e) {        } finally {            IOUtil.closeQuietly(is);            IOUtil.closeQuietly(fos);        }        return null;    }}

在初始化ImageLoader時我們會預設將幾個Loader注入到LoaderManager中,然後在載入圖片時ImageLoader會根據圖片的schema來擷取對應Loader來完成載入功能。

    /**     *      */    private LoaderManager() {        register(HTTP, new UrlLoader());        register(HTTPS, new UrlLoader());        register(FILE, new LocalLoader());    }
載入策略

載入策略就是你的圖片載入請求提交以後ImageLoader按照一個什麼規則來載入你的請求。預設就是SerialPolicy策略(FIFO),誰在隊列前面就是誰優先被執行。但是事情往往沒有那麼簡單,我們在ListView滾動時,我們希望最後添加到請求隊列的圖片優先得了載入,因此此時它們就在手機螢幕上,所以我們又添加了一個ReversePolicy策略。咦,對於這種存在各種可能性的部分,我們最不能具體化,還是要抽象!於是我定義了LoadPolicy介面,它的作用是compare兩個請求,以此來規定排序原則。

public interface LoadPolicy {    public int compare(BitmapRequest request1, BitmapRequest request2);}

因為我們的請求隊列使用的是優先順序隊列PriorityBlockingQueue,因此我們的BitmapRequest都實現了 Comparable 介面,我們在BitmapRequest的函數中將compareTo委託給LoadPolicy對象的compare。

    @Override    public int compareTo(BitmapRequest another) {        return mLoadPolicy.compare(this, another);    }

我們看看預設的載入策略,即按順序載入,先添加到隊列的請求先被執行。

/** * 順序載入策略 *  * @author mrsimple */public class SerialPolicy implements LoadPolicy {    @Override    public int compare(BitmapRequest request1, BitmapRequest request2) {        // 那麼按照添加到隊列的序號順序來執行        return request1.serialNum - request2.serialNum;    }}

逆序載入則為 :

/** * 逆序載入策略,即從最後排入佇列的請求進行載入 *  * @author mrsimple */public class ReversePolicy implements LoadPolicy {    @Override    public int compare(BitmapRequest request1, BitmapRequest request2) {        // 注意Bitmap請求要先執行最晚排入佇列的請求,ImageLoader的策略        return request2.serialNum - request1.serialNum;    }}

呵,想想這不是策略模式麼!原來模式無處不在,當你習慣之後你就會發現模式在無形之中已經運用到你的代碼了。如上所示,策略都是簡單的實現,這個策略只需要在配置ImageLoader時指定就行了,使用者也可以根據自己的需求來實現策略類,並且注入給ImageLoader。這樣就保證了靈活性、可擴充性。

總結

通過Loader和LoaderManager保證了可載入圖片來源的擴充性,即圖片可以儲存在網路上、sd卡中、res檔案夾中等等,實現一個從特定位置載入圖片的Loader,然後給這個Loader註冊一個schema,在載入圖片的時候根據圖片的路徑擷取schema,再通過schema擷取Loader,通過Loader載入圖片。

而圖片的載入策略又通過LoadPolicy這個抽象來定製,使用者可以自行實現載入策略。這樣就保證了靈活性,當然還有後期的圖片緩衝也是需要同樣的靈活性。和我在公用技術點之物件導向六大原則所說,物件導向的幾大原則最終化為幾個簡單的關鍵字: : 抽象、單一職責、最小化。領悟到了這些思想,我想你的代碼品質應該會有一個質的提升。

ImageLoader庫,圖片緩衝肯定必不可少。關於圖片的緩衝設計,還是那句老話,待我下回講解~

Github地址

SimpleImageLoader。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.