摘要:我知道最近世麟心情是錯(cuò)綜復(fù)雜,但還好的是絕大多數(shù)程序員都是特別有善心的。如果圖像數(shù)據(jù)較大就會(huì)造成對(duì)象申請(qǐng)的內(nèi)存較多,如果圖像過多就會(huì)造成內(nèi)存不夠用自然就會(huì)出現(xiàn)的現(xiàn)象。第二次將設(shè)置為再次調(diào)用函數(shù)時(shí)就能生成了。
目錄介紹
01.先看一個(gè)需求分析案例
02.Bitmap占用內(nèi)存介紹
03.影響B(tài)itmap占用內(nèi)存因素
04.圖像加載的方式
05.加載圖像內(nèi)存去哪里了
06.具體實(shí)現(xiàn)加載圖片步驟
希望世麟兄弟母親盡快好起來和南塵(世麟)認(rèn)識(shí)與網(wǎng)絡(luò),估計(jì)好多程序員都看過他的文章,我也是。雖然沒有見過面,但是微信聊過多次,感覺人非常不錯(cuò)。都具有共同的愛好,喜歡寫技術(shù)博客和開源項(xiàng)目,算得上同道中人。
對(duì)于這次他遇到的事情,我的確很佩服他那種承擔(dān)的責(zé)任和勇氣。對(duì)于任何一個(gè)出身一般的人來說,大多數(shù)家庭都是難以承擔(dān)疾病所帶來的費(fèi)用,即使有勇氣承擔(dān),那經(jīng)濟(jì)上也的確讓人壓力很大,如果可以盡綿薄之力,那就特別感謝大家呢!
雖然大多數(shù)技術(shù)平臺(tái)發(fā)這個(gè)水滴籌,有些人會(huì)表示不理解,有的甚至說會(huì)影響社區(qū)氛圍。我覺得這種擔(dān)心很正常,但是有點(diǎn)把問題放大了,首先這個(gè)是一個(gè)特別小概率的事件,并不會(huì)存在說大家都這樣做就造成不好的影響。其次有人還說,會(huì)過渡消費(fèi)社會(huì)這種同情和愛心,這種擔(dān)心挺好,但是人總是會(huì)有分辨是非的能力,如果能夠幫忙那就盡綿薄之力,如果不能幫忙那也不要亂扣帽子。
我知道最近世麟心情是錯(cuò)綜復(fù)雜,但還好的是絕大多數(shù)程序員都是特別有善心的。我始終覺得一個(gè)能夠堅(jiān)持寫技術(shù)博客,而且還寫了這么多,掘金還是以前的掘金,沒有發(fā)生變化。
程序員爸爸癱瘓14年,媽媽又這樣,幫幫南塵!
01.先看一個(gè)需求分析案例
案例說明
加載一個(gè)本地的大圖片或者網(wǎng)絡(luò)圖片,從加載到設(shè)置到View上,如何減下內(nèi)存,避免加載圖片OOM。
案例分析
在展示高分辨率圖片的時(shí)候,最好先將圖片進(jìn)行壓縮。壓縮后的圖片大小應(yīng)該和用來展示它的控件大小相近,在一個(gè)很小的ImageView上顯示一張超大的圖片不會(huì)帶來任何視覺上的好處,但卻會(huì)占用相當(dāng)多寶貴的內(nèi)存,而且在性能上還可能會(huì)帶來負(fù)面影響。
02.Bitmap占用內(nèi)存介紹
網(wǎng)絡(luò)圖片計(jì)算Bitmap的內(nèi)存大小
bitmap內(nèi)存大小 = 圖片長(zhǎng)度 x 圖片寬度 x 單位像素占用的字節(jié)數(shù)
起決定因素就是最后那個(gè)參數(shù)了,Bitmap"常見有2種編碼方式:ARGB_8888和RGB_565,ARGB_8888每個(gè)像素點(diǎn)4個(gè)byte,RGB_565是2個(gè)byte,一般都采用ARGB_8888這種。那么常見的1080*1920的圖片內(nèi)存占用就是:1920 x 1080 x 4 = 7.9M
加載本地資源計(jì)算Bitmap的內(nèi)存大小
加載一張本地資源圖片,那么它占用的內(nèi)存 = width height nTargetDensity/inDensity 一個(gè)像素所占的內(nèi)存。
詳細(xì)可以看這篇文章04.Bitmap計(jì)算內(nèi)存
正確說法,這個(gè)注意呢?計(jì)算公式如下所示
對(duì)資源文件:width height nTargetDensity/inDensity nTargetDensity/inDensity 一個(gè)像素所占的內(nèi)存;
別的:width height 一個(gè)像素所占的內(nèi)存;
03.影響B(tài)itmap占用內(nèi)存因素
影響B(tài)itmap占用內(nèi)存的因素:
圖片最終加載的分辨率;
圖片的格式(PNG/JPEG/BMP/WebP);
圖片所存放的drawable目錄;
圖片屬性設(shè)置的色彩模式;
設(shè)備的屏幕密度;
04.圖像加載的方式
獲取圖像的來源一般有三種源頭:
1.從網(wǎng)絡(luò)加載2.從文件讀取3.從資源文件加載
針對(duì)這三種情況我們一般使用BitmapFactory的
decodeStream,decodeFile,decodeResource,這三個(gè)函數(shù)來獲取到bitmap然后再調(diào)用ImageView的setImageBitmap函數(shù)進(jìn)行展現(xiàn)。
05.加載圖像內(nèi)存去哪里了
思考一下:內(nèi)存去哪里了(為什么被消耗了這么多)?
其實(shí)我們的內(nèi)存就是去bitmap里了,BitmapFactory的每個(gè)decode函數(shù)都會(huì)生成一個(gè)bitmap對(duì)象,用于存放解碼后的圖像,然后返回該引用。如果圖像數(shù)據(jù)較大就會(huì)造成bitmap對(duì)象申請(qǐng)的內(nèi)存較多,如果圖像過多就會(huì)造成內(nèi)存不夠用自然就會(huì)出現(xiàn)out of memory的現(xiàn)象。
為何容易OOM?
通過BitmapFactory的decode的這些方法會(huì)嘗試為已經(jīng)構(gòu)建的bitmap分配內(nèi)存,這時(shí)就會(huì)很容易導(dǎo)致OOM出現(xiàn)。為此每一種解析方法都提供了一個(gè)可選的BitmapFactory.Options參數(shù),將這個(gè)參數(shù)的inJustDecodeBounds屬性設(shè)置為true就可以讓解析方法禁止為bitmap分配內(nèi)存,返回值也不再是一個(gè)Bitmap對(duì)象,而是null。
06.具體實(shí)現(xiàn)加載圖片步驟為了避免OOM異常,最好在解析每張圖片的時(shí)候都先檢查一下圖片的大小,除非你非常信任圖片的來源,保證這些圖片都不會(huì)超出你程序的可用內(nèi)存。
現(xiàn)在圖片的大小已經(jīng)知道了,我們就可以決定是把整張圖片加載到內(nèi)存中還是加載一個(gè)壓縮版的圖片到內(nèi)存中。以下幾個(gè)因素是我們需要考慮的:
預(yù)估一下加載整張圖片所需占用的內(nèi)存。
為了加載這一張圖片你所愿意提供多少內(nèi)存。
用于展示這張圖片的控件的實(shí)際大小。
當(dāng)前設(shè)備的屏幕尺寸和分辨率。
比如,你的ImageView只有128x96像素的大小,只是為了顯示一張縮略圖,這時(shí)候把一張2048x1536像素的圖片完全加載到內(nèi)存中顯然是不值得的。
6.1 對(duì)圖片進(jìn)行壓縮
怎樣才能對(duì)圖片進(jìn)行壓縮呢?
通過設(shè)置BitmapFactory.Options中inSampleSize的值就可以實(shí)現(xiàn)。
比如我們有一張2048x1536像素的圖片,將inSampleSize的值設(shè)置為4,就可以把這張圖片壓縮成512x384像素。
原本加載這張圖片需要占用13M的內(nèi)存,壓縮后就只需要占用0.75M了(假設(shè)圖片是ARGB_8888類型,即每個(gè)像素點(diǎn)占用4個(gè)字節(jié))。
下面的方法可以根據(jù)傳入的寬和高,計(jì)算出合適的inSampleSize值:
public 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) { // 計(jì)算出實(shí)際寬高和目標(biāo)寬高的比率 final int heightRatio = Math.round((float) height / (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); // 選擇寬和高中最小的比率作為inSampleSize的值,這樣可以保證最終圖片的寬和高 // 一定都會(huì)大于等于目標(biāo)的寬和高。 inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; } return inSampleSize; }6.2 設(shè)置BitmapFactory.Options屬性
大概步驟如下所示
要將BitmapFactory.Options的inJustDecodeBounds屬性設(shè)置為true,解析一次圖片。注意這個(gè)地方是核心,這個(gè)解析圖片并沒有生成bitmap對(duì)象(也就是說沒有為它分配內(nèi)存控件),而僅僅是拿到它的寬高等屬性。
然后將BitmapFactory.Options連同期望的寬度和高度一起傳遞到到calculateInSampleSize方法中,就可以得到合適的inSampleSize值了。這一步會(huì)壓縮圖片。
之后再解析一次圖片,使用新獲取到的inSampleSize值,并把inJustDecodeBounds設(shè)置為false,就可以得到壓縮后的圖片了。此時(shí)才正式創(chuàng)建了bitmap對(duì)象,由于前面已經(jīng)對(duì)它壓縮了,所以你會(huì)發(fā)現(xiàn)此時(shí)所占內(nèi)存大小已經(jīng)很少了。
具體的實(shí)現(xiàn)代碼
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // 第一次解析將inJustDecodeBounds設(shè)置為true,來獲取圖片大小 final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); // 調(diào)用上面定義的方法計(jì)算inSampleSize值 options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // 使用獲取到的inSampleSize值再次解析圖片 options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); }
思考:inJustDecodeBounds這個(gè)參數(shù)是干什么的?
如果設(shè)置為true則表示decode函數(shù)不會(huì)生成bitmap對(duì)象,僅是將圖像相關(guān)的參數(shù)填充到option對(duì)象里,這樣我們就可以在不生成bitmap而獲取到圖像的相關(guān)參數(shù)了。
為何設(shè)置兩次inJustDecodeBounds屬性?
第一次:設(shè)置為true則表示decode函數(shù)不會(huì)生成bitmap對(duì)象,僅是將圖像相關(guān)的參數(shù)填充到option對(duì)象里,這樣我們就可以在不生成bitmap而獲取到圖像的相關(guān)參數(shù)。
第二次:將inJustDecodeBounds設(shè)置為false再次調(diào)用decode函數(shù)時(shí)就能生成bitmap了。而此時(shí)的bitmap已經(jīng)壓縮減小很多了,所以加載到內(nèi)存中并不會(huì)導(dǎo)致OOM。
6.3 設(shè)置bitmap到View上
將任意一張圖片壓縮成100*100的縮略圖,并在ImageView上展示。
mImageView.setImageBitmap( decodeSampledBitmapFromResource(getResources(), R.id.ycimage, 100, 100));其他介紹 01.關(guān)于博客匯總鏈接
1.技術(shù)博客匯總
2.開源項(xiàng)目匯總
3.生活博客匯總
4.喜馬拉雅音頻匯總
5.其他匯總
02.關(guān)于我的博客github:https://github.com/yangchong211
知乎:https://www.zhihu.com/people/...
簡(jiǎn)書:http://www.jianshu.com/u/b7b2...
csdn:http://my.csdn.net/m0_37700275
喜馬拉雅聽書:http://www.ximalaya.com/zhubo...
開源中國(guó):https://my.oschina.net/zbj161...
泡在網(wǎng)上的日子:http://www.jcodecraeer.com/me...
郵箱:yangchong211@163.com
阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV
segmentfault頭條:https://segmentfault.com/u/xi...
掘金:https://juejin.im/user/593943...
項(xiàng)目案例:https://github.com/yangchong2...文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/75334.html
摘要:導(dǎo)語智能手機(jī)發(fā)展到今天已經(jīng)有十幾個(gè)年頭,手機(jī)的軟硬件都已經(jīng)發(fā)生了翻天覆地的變化,特別是陣營(yíng),從一開始的一兩百到今天動(dòng)輒,內(nèi)存。恰好最近做了內(nèi)存優(yōu)化相關(guān)的工作,這里也對(duì)內(nèi)存優(yōu)化相關(guān)的知識(shí)做下總結(jié)。 導(dǎo)語 智能手機(jī)發(fā)展到今天已經(jīng)有十幾個(gè)年頭,手機(jī)的軟硬件都已經(jīng)發(fā)生了翻天覆地的變化,特別是Android陣營(yíng),從一開始的一兩百M(fèi)到今天動(dòng)輒4G,6G內(nèi)存。然而大部分的開發(fā)者觀看下自己的異常上報(bào)系...
摘要:另一種方式就是是一個(gè)簡(jiǎn)單的,方便的內(nèi)存檢測(cè)工具,可以輕易的發(fā)現(xiàn)內(nèi)存問題,還會(huì)生成更加簡(jiǎn)單清晰的報(bào)告。是一個(gè)開源的檢測(cè)內(nèi)存泄露的庫(kù)。 在開發(fā)Android應(yīng)用的過程中如果需要處理圖片或者大量數(shù)據(jù)的時(shí)候,就有可能會(huì)遇到OOM(java.lang.OutOfMemoryError),一般出現(xiàn)最多的是在創(chuàng)建Bitmap上,也有可能是在內(nèi)存中處理了大量的數(shù)據(jù)上。出現(xiàn)OOM應(yīng)用會(huì)直接崩潰,即使沒有...
閱讀 3648·2021-10-09 09:58
閱讀 1187·2021-09-22 15:20
閱讀 2495·2019-08-30 15:54
閱讀 3509·2019-08-30 14:08
閱讀 886·2019-08-30 13:06
閱讀 1817·2019-08-26 12:16
閱讀 2678·2019-08-26 12:11
閱讀 2507·2019-08-26 10:38