第十二章 Bitmap 的加載和 Cache

Bitmap 的高效加載

  1. 由於Bitmap的特殊性以及Android 對單個應用所施加的內存限制,比如16MB,這導致加載 Bitmap 的時候很容易出現內存溢出。
  2. 加載圖片:BitmapFactory 類提供了四類方法,decodeFile、decodeResource、decodeStream、decodeByteArray,分別用於支持從文件系統、資源、輸入流以及字節數組中加載出一個Bitmap 對象,decodeFile、decodeResource間接調用了decodeStream,這四類方法最終是在Android的底層實現的,對應着BitmapFactory的幾個native方法
    3. 如何高效地加載圖片?
    採用BitmapFactory.Options來加載所需尺寸的圖片,假設通過imageView來顯示圖片,很多時候ImageView並沒有圖片的原始尺寸那麼大,整張圖片加載進來再設置給ImageView顯然沒必要,通過BitmapFactory.Options就可以按一定的採樣率來加載縮小後的圖片,將縮小後的圖片在ImageView中顯示,這樣就會降低內存佔用從而在一定程度上避免OOM,提高了Bitmap加載時的性能。
  3. 通過 BitmapFactory.Options來縮放圖片,主要是用到了inSampleSize參數,即採樣率。當 inSampleSize 爲1時,採樣後的圖片和原始圖片大小相同;當 inSampleSize 爲2時,採樣後的圖片其寬高均爲原圖大小的1/2,像素數爲原圖大小的1/4。
    如何獲取採樣率?
    (1) 將BitmapFactory.OptionsinJustDecodeBounds參數設爲true並加載圖片
    (2) 從BitmapFactory.Options中取出原始寬高信息,對應於outWidth、outHeight
    (3) 根據採樣率的規則並結合目標view的所需大小計算出採樣率inSampleSize
    (4) 將 BitmapFactory.OptionsinJustDecodeBounds設爲 false 然後重新加載圖片
    inJustDecodeBounds參數 當此參數爲 true 時,BitmapFactory只會解析圖片的寬高信息,並不會真正地加載圖片,該操作是輕量級的。此時BitmapFactory獲得的圖片寬高信息和圖片的位置以及程序運行的設備有關,比如一張圖片放在不同的 drawable 目錄下,或者程序運行在不同屏幕密度的設備上,都會導致 BitmapFactory 獲取到不同的結果,原因是和 Android 的資源加載機制有關。
        BitmapFactory.decodeResource();
        BitmapFactory.decodeFile();
        BitmapFactory.decodeStream();
        BitmapFactory.decodeByteArray();

以上四個方法都是支持採樣率加載的,處理方式也是類似的。decodeStream()有些特殊,需要獲取流的文件描述符FileDescriptor,通過BitmapFactory.decodeFileDescriptor加載。

Android 中的緩存策略

1. 如何避免過多的流量消耗呢?
緩存。當程序第一次從網上加載圖片後,就將其緩存到設備上,爲了提高用戶體驗,往往還會想內存中緩存一份。當應用打算從網絡上請求一張圖片時,程序會首先從內存中獲取,如果內存中沒有就從設備中獲取,如果設備中沒有,就從網絡上下載。該緩存策略不僅適用於圖片,也適用於其他文件類型。
2. 常用緩存算法:LRU。LRU是近期最少使用算法,核心思想:當緩存滿時,會優先淘汰那些近期最少使用的緩存對象。採用LRU算法的緩存有兩種:LruCacheDiskLruCache
LruCache
內部採用一個LinkedHashMap以強引用的方式存儲外界的緩存對象。當緩存滿的時候,LruCache 會移除較早使用的緩存對象,然後再添加對象。LruCache 是線程安全的。
強引用:直接的對象引用
軟引用:當一個對象只有軟引用存在時,系統內存不足時此對象會被 gc 回收
弱引用:當一個對象只有弱引用存在時,此對象會隨時被gc回收
DiskLruCache
磁盤緩存。

ImageLoader 的實現

一個優秀的ImageLoader應該具備如下功能:
圖片的同步加載;圖片的異步加載;圖片壓縮;內存緩存;磁盤緩存;網絡拉取
圖片的同步加載:以同步的方式向調用者提供所加載的圖片,該圖片可能是從內存、磁盤和網絡中拉取的。
圖片的異步加載:調用者無需在單獨的線程中以同步的方式獲取圖片,此時ImageLoader需要自己在線程中加載圖片並將圖片設置給所需的ImageView
圖片壓縮:降低OOM概率的有效手段
內存緩存、磁盤緩存:極大提高程序效率,有效降低用戶流量。
列表錯位:對於ListView、GridView等,由於 itemView 的複用導致的列表錯位。

優化列表的卡頓現象

不要在主線程做太多的耗時操作即可提高滑動的流暢度。
1. 不要在getView中執行耗時操作。
2. 控制異步任務的執行頻率。
如果用戶可以頻繁上下滑動,就會一瞬間產生上百個異步任務,這些任務會造成線程池的擁堵並隨即帶來大量的UI更新操作,造成一定程度的卡頓?
解決:可以考慮在列表滑動的時候停止加載圖片,開啓硬件加速。

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