在Android中高效的加載大圖的方法示例
將大圖加載到內(nèi)存中總是令人痛苦,因為我們經(jīng)常會在應(yīng)用的崩潰報告中看到OOM(Out Of Memory)的bug。大家都知道,Android系統(tǒng)的內(nèi)存有限。我們必須牢記這一點。
stackoverflow上有很多關(guān)于大圖加載的問題,當你的應(yīng)用程序遇到OOM的時候,你可以選擇直接復制粘貼其中的答案來解決這個問題。因此,你完全可以略過本篇文章,但我想介紹一些加載大圖的基礎(chǔ)知識及其實際工作的原理。
我只想解釋圖片解碼背后的邏輯。我建議你使用Picasso或Glide來加載圖片。沒有必要重新發(fā)明輪子。
將圖片加載到內(nèi)存中
這很簡單。你只需要使用BitmapFactory來解碼你的圖片。
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage); imageView.setImageBitmap(bitmap);
看起來一切正常。但是我要告訴你一個問題,讓我們看看這張解碼過的圖片在內(nèi)存中實際占據(jù)的空間大小。
bitmap.getByteCount()方法將返回bitmap的大小。 這張圖片在內(nèi)存中的大小為12262248字節(jié),相當于12.3 MB。是的,你可能會感到困惑。因為這張圖片在磁盤上的實際大小約為3.5 MB,而getByteCount()方法返回的值遠大于它。原因如下:
存儲在磁盤上的圖片是被壓縮過的(以JPG,PNG或類似的格式存儲)。 一旦將圖片加載到內(nèi)存中,它就不再被壓縮,并占用盡可能多的圖片的所有像素所需的內(nèi)存空間。
加載大圖的步驟
- 獲取圖片的寬和高
- 根據(jù)圖片的寬和高計算縮放比
- 使用壓縮比將圖片加載到內(nèi)存中。
BitmapFactory.Options
BitmapFactory可以為我們提供圖片的元數(shù)據(jù)。我們可以使用這個類來實現(xiàn)第一步。
BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage, options);
我們將BitmapFactory.Options實例傳遞給BitmapFactory.decodeSource()方法。 options.inJustDecodeBounds = true 是什么意思?這句代碼是指我們不想將圖片加載到內(nèi)存中。我們只想獲取圖片的相關(guān)信息(寬度,高度等),并使用這些信息來計算縮放比例。
我們運行這段代碼和并打印圖片的信息:
options.outHeight : 1126
options.outWidth : 2000
options.bitmap : null
它只輸出了圖片的高度和寬度。
Reducing Image Size (In Memory)
現(xiàn)在我們需要計算 inSampleSize 。什么是inSampleSize? inSampleSize是BitmapFactory.Options類的一個屬性,用于設(shè)置圖片的縮放比。
如果我們有一張尺寸為1000x1000的圖片,并且在解碼之前設(shè)置inSampleSize的值為2, 那么解碼之后,我們將得到一張尺寸為500x500的圖片。 如果我們有一張尺寸為200x400的圖片,并且在解碼之前設(shè)置inSampleSize的值為5, 那么解碼之后,我們將得到一張尺寸為40x80的圖片。
BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; options.inSampleSize = 3; BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage, options);
我們可以直接這樣做嗎?不能,因為我們不知道圖片大小是多少。如果它是小圖片,并且我們使其更小,那么我們的用戶可以看到的就是一些像素而不是圖像。有一些圖片需要縮放5倍,另一些圖片則需要縮放2倍。我們不能將縮放比設(shè)置為一個常數(shù),所以我們必須根據(jù)圖片的大小來計算它的值。
如何計算inSampleSize的值取決于您。我的意思是,你可以根據(jù)你的需要編寫inSampleSize的計算方法。在android官方文檔中,計算結(jié)果是2的冪次方。
options.inSampleSize = calculateInSampleSize(options, 500,500); options.inJustDecodeBounds = false; Bitmap smallBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage, options);
這里我們將 inJustDecodeBounds 的值設(shè)為false,并獲得了一個bitmap對象?,F(xiàn)在,bitmap.getByteCount()方法返回的圖片大小是3.1 MB。這是它在內(nèi)存中的大小。正如我之前說過的,圖片存儲在磁盤上時會被壓縮。當我們將它們加載到內(nèi)存中時它們會占據(jù)更大的內(nèi)存空間。通過上面這種方法,我們將它在內(nèi)存中占據(jù)的空間大小從12.3 MB減少到了3.1 MB,減少了75%。
Reducing Image Size (In Disk)
我們還可以使用Bitmap的 compress 方法對磁盤上的圖片進行壓縮。
我們來看看在不改變圖片質(zhì)量的情況下圖片被壓縮后的大小。 100 表示與原圖保持相同的質(zhì)量。
ByteArrayOutputStream bos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos); byte[] bitmapdata = bos.toByteArray();
通過計算得到圖片在磁盤上的大小為1.6 MB。
我們把compress方法中的質(zhì)量參數(shù)改為50,并再次計算圖片大小。
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, bos);
通過計算得到圖片在磁盤上的大小為24.4 KB。
注意:在改變compress方法中的質(zhì)量參數(shù)的時候,壓縮格式應(yīng)該是.JPEG。設(shè)置為PNG格式的時候,修改是無效的。
下面是一張對比效果圖:
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android實現(xiàn)多參數(shù)文件和數(shù)據(jù)上傳
這篇文章主要為大家詳細介紹了Android實現(xiàn)多參數(shù)文件和數(shù)據(jù)上傳,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-12-12Android RecyclerView添加上拉加載更多功能
這篇文章主要為大家詳細介紹了Android RecyclerView如何添加上拉加載更多功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-10-10Android 使用Vitamio打造自己的萬能播放器(1)——準備
本文主要介紹Android Vitamio,在Android開發(fā)視頻播放器的時候,大家經(jīng)常會遇到系統(tǒng)版本和不同的Android手機不同導致開發(fā)的軟件不能完美適用,這里給大家介紹個播放器插件可以適應(yīng)所有Android設(shè)備2016-07-07View中如何進行手勢識別onFling動作實現(xiàn)介紹
下面我們就以實現(xiàn)手勢識別的onFling動作,在CwjView中我們從View類繼承,當然大家可以從TextView等更高層的界面中實現(xiàn)觸控,感興趣的朋友可以了解下哈2013-06-06Android BroadcastReceiver常見監(jiān)聽整理
這篇文章主要介紹了Android BroadcastReceiver常見監(jiān)聽整理的相關(guān)資料,需要的朋友可以參考下2016-10-10android開發(fā)之調(diào)用手機的攝像頭使用MediaRecorder錄像并播放
我們玩玩手機的錄像功能吧;今天做個調(diào)用手機的攝像頭使用MediaRecorder錄像并播放的DEMO,源碼很詳細,感興趣的朋友可以了解下,希望本文對你有幫助2013-01-01Android仿網(wǎng)易新聞圖片詳情下滑隱藏效果示例代碼
這篇文章主要給大家介紹了關(guān)于利用Android如何仿網(wǎng)易新聞圖片詳情下滑隱藏效果的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2018-07-07