在Android開發中,咱們不免會遇到加載圖片的場景。不論是網絡圖片、資源圖片或者是SD卡中的圖片,都須要加載到內存中使用。若是不能合理處理圖片,可能會致使OOM的問題或者其餘性能問題,接下就討論下Android中圖片資源處理的幾種經常使用的方式。android
在Android中開發的時候都會用到不少圖片素材,對於某些背景圖片、各類圖標或者其餘一些提示圖片咱們一般會放到res目錄中的drawable中。緩存
咱們知道在res目錄下有不少drawable目錄,好比:drawable、drawable-hdpi、drawable-mdpi等。這些目錄對應了不一樣密度的屏幕,在不一樣密度的屏幕下會優先從對應目錄下取圖片資源。網絡
目錄名稱 | 密度(Density) |
---|---|
res/drawable | 0 |
res/drawable-ldpi | 120 |
res/drawable-mdpi | 160 |
res/drawable-hdpi | 240 |
res/drawable-xhdpi | 320 |
res/drawable-xxdpi | 480 |
這六種目錄表明了目前市面上Android機型不一樣的6中密度的屏幕。框架
注意:res/drawable目錄的密度爲0,不是說有機型的屏幕密度爲0。這是默認密度,在不一樣機型下默認密度不同。ide
Android在加載資源圖片時,會先獲取當前設備的屏幕密度,而後根據屏幕密度去找圖片資源。若是沒有在對應的文件夾下找到圖片資源,就會採起就近原則,從與屏幕密度最相近的圖片資源目錄獲取。若是都沒有就只能從默認的資源目錄下獲取(也就是res/drawable)。性能
在獲取到圖片資源時,若是密度不匹配,Android會對圖片進行處理。好比在res/drawable-mdpi找到了圖片,可是設備屏幕密度是xxdpi的,那麼Android就會按照3倍大小縮放這張圖片。根據圖片內存的計算公式(圖片高度 x 圖片寬度 x 一個像素佔用的內存大小)。好比:一張800x480的圖片原來佔用內存大約是1.46M,增長3倍後圖片是3200x1920,佔用內存大約是23M。而通常Android系統分配給每一個進程的內存也才一百多M,在低配手機中很容易就產生OOM。學習
針對上面的狀況,如何處理資源文件呢?由於Android拿到低密度的圖片時,在高密度設備會將其放大。因此在添加資源文件時,應該優先使用高品質圖片從高密度的目錄往下放。優化
Bitmap類型的圖片也是在開發中常常用到的。對於Bitmap圖片若是不加處理直接使用的話,也很容易致使OOM。由於會有一些佔用很大的圖片被加載到內存中,而真正的需求可能並不須要這麼大的圖片。spa
接下來的內容大多來自於Google推薦的一種處理Bitmap圖片的方法。連接在下面,感興趣的同窗也能夠直接閱讀文檔。code
developer.android.com/topic/perfo…
在Google的方案中,主要的思想是按需加載Bitmap。所謂的按需加載,就是根據圖片的尺寸和要加載圖片的ImageView的尺寸對Bitmap進行壓縮處理。
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
複製代碼
上面的代碼會獲取到Bitmap圖片的寬、高、MimeType。同時這裏有個參數是比較重要的,inJustDecodeBounds這個參數設爲true的時候不會在內存中分配Bitmap的空間,只是獲取到了Bitmap圖片的寬高等信息。
public static int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
//若是Bitmap圖片寬高大於ImageView寬高,就縮放圖片
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;
}
}
return inSampleSize;
}
複製代碼
上面的代碼經過圖片的尺寸計算Bitmap圖片的縮放比例。最終獲得的結果inSampleSize就是須要縮放的比例。
public static 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);
}
複製代碼
這一步是獲取獲得最終的Bitmap圖片,能夠看到BitmapFactory.Options options的inSampleSize是縮放比例,在獲取圖片以前,將inJustDecodeBounds設置爲false,而後再次調用decode方法就得到了最終的Bitma對象。
在處理圖片時,特別是網絡圖片若是咱們想要高效的利用圖片資源。這個時候使用圖片加載框架是一個很好的選擇。好比:Glide框架。這也是Google推薦的圖片加載框架。
圖片加載框架不只能幫助咱們處理圖片。同時還能經過緩存複用圖片,提升圖片的利用率。
在Android開發中,圖片的處理幾乎是因此應用都要面對的場景,可以瞭解一些圖片的優化的小技巧,可以提升咱們在開發中的效率與質量。若是各位同窗有更好的方法,歡迎在評論區討論,你們共同窗習。