Android中的縮略圖加載-不浪費一點多余的內存


1. Why,為什么要加載縮略圖?

有的時候不需要展示原圖,只需展示圖片的縮略圖,可以節省內存。比如:網易新聞中的圖片瀏覽,左邊展示的小獅子圖片就是一個縮略圖,點擊這個圖片,才會展示原圖。

\ \

2. How,怎么做呢?

http://developer.android.com/training/displaying-bitmaps/load-bitmap.html給出了一個方法,可以加載一個圖片的縮略圖。
BitmapFactory#decodeFile (String pathName, BitmapFactory.Options opts),opts可以指定inJustDecodeBounds和inSampleSize兩個參數。當指定inJustDecodeBounds時候,只解析圖片的長度和寬度,不載入圖片。當指定inSampleSize的時候,會根據inSampleSize載入一個縮略圖。 比如inSampleSize=4,載入的縮略圖是原圖大小的1/4。
要設置inSampleSize是多少呢?假設原圖是1500x700的,我們給縮略圖留出的空間是100x100的。那么inSampleSize=min(1500/100, 700/100)=7。我們可以得到的縮略圖是原圖的1/7。這里如果你要問15:7的圖片怎么顯示到1:1的區域內,請去看ImageView的scaleType屬性。
但是事實沒有那么完美,雖然設置了inSampleSize=7,但是得到的縮略圖卻是原圖的1/4,原因是inSampleSize只能是2的整數次冪,如果不是的話,向下取得最大的2的整數次冪,7向下尋找2的整數次冪,就是4。
怎么才能不浪費內存呢?大熊同學找到一個方法:Bitmap#createScaledBitmap (Bitmap src, int dstWidth, int dstHeight, boolean filter),該方法可以將一個Bitmap生成指定大小的BItmap,該方法可以放大圖片也可以縮小圖片。

最終縮略圖加載過程:

1. 使用inJustDecodeBounds,讀bitmap的長和寬。
2. 根據bitmap的長款和目標縮略圖的長和寬,計算出inSampleSize的大小。
3. 使用inSampleSize,載入一個大一點的縮略圖A
4. 使用createScaseBitmap,將縮略圖A,生成我們需要的縮略圖B。
5. 回收縮略圖A。

 

3. Notice,需要注意的事情

 

createScaseBitmap如果原圖和目標縮略圖大小一致,那么不會生成一個新的bitmap直接返回bitmap,因此,回收的時候,要判斷縮略圖A是否就是縮略圖B,如果說是的話,不要回收。

4. 代碼

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/**
  */
public class BitmapUtils {
     private static int calculateInSampleSize(BitmapFactory.Options options,
             int reqWidth, int reqHeight) {
         final int height = options.outHeight;
         final int width = options.outWidth;
         int inSampleSize = 1 ;
         if (height > reqHeight || width > reqWidth) {
             final int halfHeight = height / 2 ;
             final int halfWidth = width / 2 ;
             while ((halfHeight / inSampleSize) > reqHeight
                     && (halfWidth / inSampleSize) > reqWidth) {
                 inSampleSize *= 2 ;
             }
         }
         return inSampleSize;
     }
 
     // 如果是放大圖片,filter決定是否平滑,如果是縮小圖片,filter無影響
     private static Bitmap createScaleBitmap(Bitmap src, int dstWidth,
             int dstHeight) {
         Bitmap dst = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false );
         if (src != dst) { // 如果沒有縮放,那么不回收
             src.recycle(); // 釋放Bitmap的native像素數組
         }
         return dst;
     }
 
     // 從Resources中加載圖片
     public static Bitmap decodeSampledBitmapFromResource(Resources res,
             int resId, int reqWidth, int reqHeight) {
         final BitmapFactory.Options options = new BitmapFactory.Options();
         options.inJustDecodeBounds = true ;
         BitmapFactory.decodeResource(res, resId, options); // 讀取圖片長款
         options.inSampleSize = calculateInSampleSize(options, reqWidth,
                 reqHeight); // 計算inSampleSize
         options.inJustDecodeBounds = false ;
         Bitmap src = BitmapFactory.decodeResource(res, resId, options); // 載入一個稍大的縮略圖
         return createScaleBitmap(src, reqWidth, reqHeight); // 進一步得到目標大小的縮略圖
     }
 
     // 從sd卡上加載圖片
     public static Bitmap decodeSampledBitmapFromFd(String pathName,
             int reqWidth, int reqHeight) {
         final BitmapFactory.Options options = new BitmapFactory.Options();
         options.inJustDecodeBounds = true ;
         BitmapFactory.decodeFile(pathName, options);
         options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
         options.inJustDecodeBounds = false ;
         Bitmap src = BitmapFactory.decodeFile(pathName, options);
         return createScaleBitmap(src, reqWidth, reqHeight);
     }
}

5. 測試代碼

代碼下載鏈接 http://download.csdn.net/detail/u011267546/7485045

在drawable-xxhdpi目錄下,一共有四種大圖,每個平均5-6MB,一共22.9MB。如果原圖加載很容易就崩潰了。如果使用上面的方法加載的話,只加載了234KB。這里說一下234KB怎么來的,4個imageView,目標尺寸都是75dip*50dip,在我的手機GalaxyNexus上面,轉化為px之后是150px*100px=15000個像素,每個像素使用ARGB_8888方式存儲,需要4個字節。一張圖片需要15000*4=60000字節,一共有4個Bitmap,那么就是60000*4=240000字節=234.375 KB。

 

如果是布滿一個屏幕,至少需要多少內存呢?我的手機是768*1280像素,ARGB_8888方式存儲,每個像素4個字節,那么就是768*1280*4=3840KB=3.75MB。所以,緩存3屏幕圖像的話,也就11MB左右。做內緩存的時候,有必要考慮下這個問題。

 

\


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM