## 12.1 Bitmap的高速加載
(1)Bitmap是如何加載的?
`BitmapFactory`類提供了四類方法:`decodeFile`、`decodeResource`、`decodeStream`和`decodeByteArray`從不同來源加載出一個Bitmap對象,最終的實現是在底層實現的。
如何高效加載Bitmap?
采用`BitmapFactory.Options`按照一定的采樣率來加載所需尺寸的圖片,因為imageview所需的圖片大小往往小于圖片的原始尺寸。
(2)BitmapFactory.Options的`inSampleSize`參數,即采樣率
官方文檔指出采樣率的取值應該是2的指數,例如k,那么采樣后的圖片寬高均為原圖片大小的 1/k。
如何獲取采樣率?
下面是常用的獲取采樣率的代碼片段:
~~~
public Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
if (reqWidth == 0 || reqHeight == 0) {
return 1;
}
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
Log.d(TAG, "origin, w= " + width + " h=" + height);
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and
// keeps both height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
Log.d(TAG, "sampleSize:" + inSampleSize);
return inSampleSize;
}
~~~
將`inJustDecodeBounds`設置為true的時候,BitmapFactory只會解析圖片的原始寬高信息,并不會真正的加載圖片,所以這個操作是輕量級的。需要注意的是,這個時候BitmapFactory獲取的圖片寬高信息和圖片的位置以及程序運行的設備有關,這都會導致BitmapFactory獲取到不同的結果。
## 12.2 Android中的緩存策略
(1)最常用的緩存算法是LRU,核心是當緩存滿時,會優先淘汰那些近期最少使用的緩存對象,系統中采用LRU算法的緩存有兩種:`LruCache`(內存緩存)和`DiskLruCache`(磁盤緩存)。
(2)LruCache是Android 3.1才有的,通過support-v4兼容包可以兼容到早期的Android版本。LruCache類是一個線程安全的泛型類,它內部采用一個`LinkedHashMap`以強引用的方式存儲外界的緩存對象,其提供了get和put方法來完成緩存的獲取和添加操作,當緩存滿時,LruCache會移除較早使用的緩存對象,然后再添加新的緩存對象。
(3)DiskLruCache磁盤緩存,它不屬于Android sdk的一部分,[它的源碼可以在這里下載](https://android.googlesource.com/platform/libcore/+/android-4.1.1_r1/luni/src/main/java/libcore/io/DiskLruCache.java)
DiskLruCache的創建、緩存查找和緩存添加操作
(4)ImageLoader的實現?[具體內容看源碼](https://github.com/singwhatiwanna/android-art-res/blob/master/Chapter_12/src/com/ryg/chapter_12/loader/ImageLoader.java)
功能:圖片的同步/異步加載,圖片壓縮,內存緩存,磁盤緩存,網絡拉取
## 12.3 ImageLoader的使用
避免發生列表item錯位的解決方法:給顯示圖片的imageview添加`tag`屬性,值為要加載的圖片的目標url,顯示的時候判斷一下url是否匹配。
優化列表的卡頓現象
(1)不要在getView中執行耗時操作,不要在getView中直接加載圖片,否則肯定會導致卡頓;
(2)控制異步任務的執行頻率:在列表滑動的時候停止加載圖片,等列表停下來以后再加載圖片;
(3)使用硬件加速來解決莫名的卡頓問題,給Activity添加配置`android:hardwareAccelerated="true"`。
本章的精華就是作者寫的[ImageLoader類](https://github.com/singwhatiwanna/android-art-res/blob/master/Chapter_12/src/com/ryg/chapter_12/loader/ImageLoader.java),建議閱讀源碼感受下。
- 前言
- 讀書筆記(1)第1章 Activity的生命周期和啟動模式
- 讀書筆記(2)第2章 IPC機制
- 讀書筆記(3)第3章 View的事件體系
- 讀書筆記(4)第4章 View的工作原理
- 讀書筆記(5)第5章 理解RemoteViews
- 讀書筆記(6)第6章 Android的Drawable
- 讀書筆記(7)第7章 Android動畫深入分析
- 讀書筆記(8)第8章 理解Window和WindowManager
- 讀書筆記(9)第9章 四大組件的工作過程
- 讀書筆記(10)第10章 Android的消息機制
- 讀書筆記(11)第11章 Android的線程和線程池
- 讀書筆記(12)第12章 Bitmap的加載和Cache
- 讀書筆記(13)第13章 綜合技術