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