KJFrameForAndroid架構學習----高效設定網狀圖片,

來源:互聯網
上載者:User

KJFrameForAndroid架構學習----高效設定網狀圖片,

KJFrameForAndroid架構項目地址:https://github.com/kymjs/KJFrameForAndroid

或備用地址http://git.oschina.net/kymjs/KJFrameForAndroid

KJFrameForAndroid開發群:257053751


我們都知道,電腦讀取資料時:記憶體的讀取速度是最快的,然後是檔案的讀取速度,最後是網路資源的讀取。

    如果每次載入同一張圖片都要從網路擷取,那代價實在太大了。所以同一張圖片只要從網路擷取一次就夠了,然後在本機快取起來,之後載入同一張圖片時就 從緩衝中載入就可以了。從記憶體緩衝讀取圖片是最快的,但是因為Android對每個應用所能使用的記憶體容量都有限制,所以最好再加上檔案快取。檔案快取空間也不是無限大的,容量越大讀取效率越低,這個很好理解,從沙漠中找出丟失的一根針和從盤子中找到一根針,哪個容易一想即知。因此我們常設定一個限定大小比如10M。

所以,載入圖片的流程應該是:
    1、先從記憶體緩衝中擷取,取到則返回,取不到則進行下一步;
    2、從檔案快取中擷取,取到則返回並更新到記憶體緩衝,取不到則進行下一步;
    3、從網路下載圖片,並更新到記憶體緩衝和檔案快取。

如果您只想瞭解檔案快取與記憶體緩衝公用,請查看下一篇博文。

    在過去,我們經常會使用一種非常流行的記憶體緩衝技術的實現,即軟引用或弱引用 (SoftReference or WeakReference)。但是根據Google的描述:現在已經不再推薦使用這種方式了,因為從 Android 2.3 (API Level 9)開始,記憶體回收行程會更傾向於回收持有軟引用或弱引用的對象,這讓軟引用和弱引用變得不再可靠。另外,Android 3.0 (API Level 11)中,圖片的資料會儲存在本地的記憶體當中,因而無法用一種可預見的方式將其釋放,這就有潛在的風險造成應用程式的記憶體溢出並崩潰。

    因此,我們更多的是去使用lru演算法(Least Recently Used 近期最少使用演算法)最初這種演算法是用在作業系統調度上的。他的原理是通過個線性表格儲存體資料,並記錄資料每次調用次數,越常用到的排名就越靠前,越少用到的排名就越靠後,如果是一個新加入的資料,就會把它放在第一位,然後移除掉排名最後一位的資料。這裡是KJFrameForAndroid架構中關於記憶體lru演算法的實現方式 LruMemoryCache

既然是載入網狀圖片,那麼當然需要載入的控制項和網狀圖片地址作為參數,樣本如下所示

private void loadImage(ImageView imageView, String imageUrl) {    // 首先訪問記憶體緩衝,判斷圖片是否已經存在    Bitmap bitmap = mMemoryCache.get(StringUtils.md5(imageUrl));    if (bitmap != null) {            imageView.setImageBitmap(bitmap);        }else{         //否則就去網路下載        BitmapWorkerTask task = new BitmapWorkerTask(imageView);            task.execute(imageUrl);    }}


    至於實際下載的方法,我就不詳細講解了,相信大家都能想到,就是一個網路請求,然後下載圖片,再轉成bitmap,最後設定為控制項圖片。然而這裡有一個需要注意的重要地方,就是當我們把圖片下載成功後要記得在mMemoryCache中緩衝起來。
這裡是KJFraemForAndroid應用開發架構中的一段網狀圖片載入的代碼:

  /********************* 非同步擷取Bitmap並設定image的任務類 *********************/    private class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {        private View imageView;         public BitmapWorkerTask(View imageview) {            this.imageView = imageview;        }         @Override        protected Bitmap doInBackground(String... params) {            Bitmap bitmap = null;            //有關這個方法,下面的文章將會講解            byte[] res = downloader.loadImage(params[0]);            if (res != null) {                bitmap = BitmapCreate.bitmapFromByteArray(res, 0, res.length,                        config.width, config.height);            }            if (bitmap != null && config.openMemoryCache) {                // 圖片載入完成後緩衝到LrcCache中                putBitmapToMemory(params[0], bitmap);                if (config.isDEBUG)                    KJLoger.debugLog(getClass().getName(),                            "put to memory cache\n" + params[0]);            }            return bitmap;        }         @Override        protected void onPostExecute(Bitmap bitmap) {            super.onPostExecute(bitmap);            if (imageView instanceof ImageView) {                if (bitmap != null) {                    ((ImageView) imageView).setImageBitmap(bitmap);                }            } else {                imageView.setBackgroundDrawable(new BitmapDrawable(bitmap));            }            if (config.callBack != null)                config.callBack.imgLoadSuccess(imageView);            taskCollection.remove(this);        }    }


深入理解圖片載入在實際項目中的應用

    以上只是網狀圖片載入並緩衝的基本操作,那麼我們如果在實際項目中使用必須考慮到代碼的完備性與可擴充性。

    ①比如我們想指定圖片的大小,雖然我們可以通過設定view的固定寬高來強製圖片的顯示大小,但如果是一張幾兆的圖片,而我們只需要15*15解析度大小的顯示地區,這顯然是浪費的;

    ②又比如,我們希望控制項在網路正在下載圖片時先顯示一個預設的圖片(比如一個灰色的頭像)又或者是圖片下載的時候顯示一個環形的進度條,那麼上面的代碼是沒有辦法的;

    ③再比如,我們希望圖片的下載方式有多種,對於不同網站來源有不同的下載方式。。。。


這些種種特殊的需求告訴我們,上面的代碼完全沒有辦法做到。那麼為了控制項的完備性與可擴充性,我們就需要一個配置器、一個顯示器、一個下載器。。等等根據特殊需要而添加的外掛程式式開發。

    因此,我們可以看到在KJFrameForAndroid架構的org.kymjs.aframe.bitmap包下有著KJBitmapConfig、I_ImageLoder、I_Display等等用final修飾的類或者協議介面。

    比如KJBitmapConfig類,是一個用final修飾的配置器類,通過這個配置器,我們就可以動態對每一張下載的圖片設定寬高、以及記憶體大小等。而I_ImageLoder、I_Display則是兩個協議介面,分別定義了下載器和顯示器的方法,這裡實際上是GoF設計模式中Factory 方法模式的應用,只是這裡的工廠實際上並不是用來建立對象,而是用來定義顯示方法或下載方法的,不論是哪個實現了I_ImageLoder抽象工廠的實際工廠,都必須有一個載入圖片的方法。那麼在項目的實際應用中,就可以不管這個下載器的實際工廠是什麼,只需要調用工廠的載入圖片的方法就行了。

/** * 圖片載入介面協議,可自訂實現此協議的下載器 *  * @explain 採用Factory 方法模式設計的下載器,本類也是一個抽象工廠類,用於生產byte[]產品 * @author kymjs(kymjs123@gmail.com) * @version 1.0 * @created 2014-7-11 */public interface I_ImageLoder {    public byte[] loadImage(String imageUrl); }


這裡我們應該就可以知道上面的程式碼片段中有這麼一段代碼原因了
byte[] res = downloader.loadImage(params[0]);
downloader實際上就是下載器的抽象工廠。

至於顯示器的邏輯和下載器是一樣的,這裡我就不詳細介紹了,大家可以自己查看KJFrameForAndroid的原始碼或樣本項目。

這裡是I_ImageLoader下載器協議的一個實作類別 Downloader.java,大家當然也可以根據自己的需要去實現自己的下載器,這完全沒有任何作為擴充試開發,這對於圖片設定代碼本身沒有任何影響。





聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.