1. 程式人生 > >安卓權威編程指南 挑戰練習 24章 預加載以及緩存

安卓權威編程指南 挑戰練習 24章 預加載以及緩存

返回 position 是否 cache 編程 load 指南 存儲策略 ktr

24.7 挑戰練習:預加載以及緩存

應用中並非所有任務都能即時完成,對此,大多用戶表示理解。不過,即使是這樣,開發者們也一直在努力做到最好。為了讓應用反應更快,大多數現實應用都通過以下兩種方式增強自己的代碼:? 增加緩存層

? 預加載圖片

緩存指存儲一定數目 Bitmap 對象的地方。這樣,即使不再使用這些對象,它們也依然存儲在那裏。

緩存的存儲空間有限,因此,在緩存空間用完的情況下,需要某種策略對保存的對象做一定的取舍。許多緩存機制使用一種叫作LRU(least recently used,最近最少使用)的存儲策略。基於該種策略,當存儲空間用盡時,緩存會清除最近最少使用的對象。Android支持庫中的 LruCache 類實現了LRU緩存策略。

作為第一個挑戰練習,請使用LruCache 為 ThumbnailDownloader 增加簡單的緩存功能。這樣,每次下載完 Bitmap 時,將其存入緩存中。隨後,準備下載新圖片時,應首先查看緩存,確認它是否存在。緩存實現完成後,即可使用它進行預加載。預加載是指在實際使用對象前,就預先將處理對象加載到緩存中。

這樣,在顯示 Bitmap 時,就不會存在下載延遲。實現完美的預加載比較棘手,但對用戶來說,良好的預加載是一種截然不同的體驗。作為第二個稍有難度的挑戰練習,請在顯示 GalleryItem 時,為前十個和接下來十個 GalleryItem 預加載 Bitmap



1.增加緩存層

ThumbnailDownloader增加:

private LruCache<String, Bitmap> mBitmapLruCache;

在onLooperPrepared()方法中實例化這一對象:

//onLooperPrepared()在Looper首次檢查消息隊列之前調用的。
    @Override
    protected void onLooperPrepared() {
        mRequestHandler = new Handler() {
            @Override
            public
void handleMessage(Message msg) { //隊列中的下載消息取出並可以處理時,就會觸發調用Handler.handleMessage()方法。 if (msg.what == MESSAGE_DOWNLOAD) { T target = (T) msg.obj; Log.i(TAG, "Got a request for URL" + mRequestMap.get(target)); handleRequest(target); } } }; mBitmapLruCache = new LruCache<String, Bitmap>(24 * 1024); //實際中,LruCache分配的內存應該進行動態計算 }

修改handleRequest()方法:



private void handleRequest(final T target) {
    try {
        final String url = mRequestMap.get(target);

        final Bitmap bitmap;
        if (url == null) {
            return;
        }

        if (mBitmapLruCache.get(url) != null) {
            bitmap = mBitmapLruCache.get(url);
        } else {
            byte[] bitmapBytes = new FlickrFetcher().getUrlBytes(url);
            bitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length);//將返回的字節數組轉化為位圖
        }

        if (mBitmapLruCache.get(url) == null) {
            mBitmapLruCache.put(url, bitmap);
            Log.d(TAG, "handleRequest:  Put ---"  + url);
        }
        Log.i(TAG, "Bitmap Created");
        mResponseHandler.post(new Runnable() {
            @Override
            public void run() {
                if (mRequestMap.get(target) != url || mHasQuit) {  //再次檢查requestMap 因為RecyclerView會循環使用其視圖,
                    return;
                }
                mRequestMap.remove(target); //在requesMap中刪除配對的PhotoHolder-URL
                mThumbnailDownloadListener.onThumnailDownloaded(target, bitmap);
            }
        });
    } catch (IOException ioe) {
        Log.e(TAG, "Error downloading image", ioe);
    }
}

2.預加載:

PhotoGalleryFragment中
@Override
        public void onBindViewHolder(PhotoHolder photoHolder, int position) {

            GalleryItem galleryItem = mGalleryItems.get(position);
            Drawable placeholder = getResources().getDrawable(R.drawable.bill_up_close);
            photoHolder.bindDrawable(placeholder);
            mThumbnailDownloader.queueThumbnail(photoHolder, galleryItem.getUrl());
            for(int i=position-10; i<position + 10; i++) {  //這裏必須要put進LruCache之後才會顯示圖片。十分耗時
                if (i < 0 || i == position || i >= mItems.size()) {
                    continue;
                }
                GalleryItem item = mGalleryItems.get(i);
                mThumbnailDownloader.putUrl(item.getUrl());
            }

ThumbnailDownloader中:

public
void putUrl(final String url){ if(mBitmapLruCache.get(url) == null){ new Thread(new Runnable() { @Override public void run() { try{ byte[] bitmapBytes = new FlickrFetcher().getUrlBytes(url); Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length); mBitmapLruCache.put(url,bitmap); }catch(Exception e){ e.printStackTrace(); } } }).start(); } }

安卓權威編程指南 挑戰練習 24章 預加載以及緩存