模擬volley寫小型圖片下載及緩存框架

寫SDK的時候,碰到一個小的需求,銀行的小圖標需要訪問服務器下載,並且要緩存在本地。
因爲SDK項目中銀行圖標類似圖片並不是很多,如果使用第三方框架的話太大,大材小用,而且類似加載圖片的第三方很多,如果SDK接入了volley,但是接入我們SDK的app卻使用了picasso,會導致同樣功能代碼的重複,方法數也容易超標。
所以就要自己寫一個小的框架,簡要描述就是給出圖片url,第一次進行網絡訪問,並緩存在本地(包括內存和硬盤緩存)。後續都可以從本地讀取。(不處理服務器給出的頭部,例如有效期等等)。
代碼:
git clone https://github.com/LxxCaroline/MyApplication.git

該小框架是主要模仿volley而寫的,有類似的幾個class,包括RequestQueue, ImageRequest, NetworkDispatcher, CacheDispatcher, HttpEngine(類似HurlStack), ImageCache, NetworkImageView

ImageRequest主要是封裝了請求,包括url,listener,bitmap,isCanceled,tracer(Arraylist主要是記錄該request流程的走向)
RequestQueue是中央處理樞紐,ImageRequest交給RequestQueue來處理,由RequestQueue開啓網絡線程NetworkDispatcher和緩存線程CacheDispatcher來處理一些將要處理的ImageRequest。一般ImageRequest是先通過CacheDispatcher來獲取,如果獲取不到,則通過NetworkDispatcher來獲取,之後再寫入到Cache中。ImageCache主要是來讀寫Cache的,這裏用到了LruCache和DiskLruCache。
NetworkImageView是專門用來加載圖片的,HttpEngine就是真正訪問網絡的地方。

在RequestQueue中有幾個重要的變量:

private Map<String, Queue< ImageRequest >> mWaitingRequests;
private PriorityBlockingQueue<ImageRequest> mNetworkQueue;
private PriorityBlockingQueue<ImageRequest> mCacheQueue;

第一個變量是記錄當往RequestQueue中加入request的時候,先檢測是否有相同url的request,如果有,則將該request加入到相同url的queue中去,這樣當第一個相同url的request返回的時候,可以把結果分享給queue中的request。
第二個參數是維護將要被網絡訪問的request隊列。
第三個參數是維護將要訪問Cache的request隊列。
剛剛說到RequestQueue中會開啓網絡和cache線程,一般來說cache訪問會很快,所以只用開一個cache線程。network比較慢,所以如果你項目中圖片訪問量大的話,則需要多開幾個線程,如果圖片訪問量不大的話,開一至兩個線程就可以了。
一個cache線程的話,都從requestQueue的mCacheQueue中取,而多個network線程的話,都從requestQueue的mNetworkQueue中取(所有線程共享)。
priorityBlockingQueue是無界隊列,並且具有優先級,可以以一定的順序去讀取request,至於如何定優先級,用戶可以自己定義,例如先來後到,或給某些request一些高的優先級。

在NetworkImageView中,拿到bitmap後,需要給自己setImageBitmap,但是注意,需要在主線程中進行。
原來NetworkImageView的代碼:

private ImageRequest request = null;
private RequestQueue queue;

public void setRequestQueue(RequestQueue queue){
    this.queue = queue;
}

public void setImageUrl(String url) {
    if (request != null) {
        request.setListener(null);
    }
    request = new ImageRequest(url);
    request.setListener(this);
    queue.addRequest(request);
}

@Override
public void onResponse(final Bitmap bitmap) {
    Log.d("RequestQueue-View", "setBitmap " + (bitmap != null));
    post(new Runnable() {
        @Override
        public void run() {
            Log.d("RequestQueue-View", "setBitmap succ");
            setImageBitmap(bitmap);
        }
    });
}

@Override
protected void onDetachedFromWindow() {
    if (request != null) {
        request.isCanceled = true;
        request.setListener(null);
    }
    super.onDetachedFromWindow();
}

發現在onResponse函數中,只打印了第一個log,第二個卻沒打印(也就是說runnable中的內容都沒有執行),導致圖片未顯示。。。
後來查到post(runnable)在view沒有被attach到window之前,是沒有效果的,後來代碼改成如下:

public void setImageUrl(String url) {
    if (request != null) {
        request.setListener(null);
    }
    request = new ImageRequest(url);
    request.setListener(this);
    if (isAttachedToWindow()) {
        queue.addRequest(request);
    }
}

@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    if (request != null) {
        queue.addRequest(request);
    }
}

接下來說下DiskLruCache,這個是硬盤緩存技術,這個類的代碼需從網上下,並非google撰寫,但得到官方認可。具體說明可以看這篇文章:
Android DiskLruCache緩存完全解析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章