撩一撩B妹(BitMap)

這個是前同事留下來的文章

為什么要撩BitMap?

做android必然會撩到BitMap擅耽,撩過BitMap的都知道盗飒,BitMap可不是你想撩就能撩挨摸,她脾氣可是很不好的栅炒,是一言不合就OOM.So 學(xué)好撩妹姿勢是多么的重要

歷史演進(jìn)

言歸正傳帘不,BitMap會出現(xiàn)OOM其實是有歷史原因的:

  • 在Android 2.2 (api level 8)以及之前说莫,當(dāng)垃圾回收和線程是不能并發(fā)的,當(dāng)發(fā)生垃圾回收的時候寞焙,線程就會被暫停储狭,這就會導(dǎo)致延遲滯后甚至卡頓,系統(tǒng)效率低下捣郊。從Android 2.3開始辽狈,添加了并發(fā)垃圾回收的機制, 這意味著在一個Bitmap不再被引用之后呛牲,它所占用的內(nèi)存會被立即回收刮萌。

  • 在Android 2.3.3 (API level 10)以及之前, 一個Bitmap的像素級數(shù)據(jù)(pixel data)是存放在Native內(nèi)存空間中的。 這些數(shù)據(jù)與Bitmap本身是隔離的娘扩,Bitmap本身被存放在Dalvik堆中着茸。我們無法預(yù)測在Native內(nèi)存中的像素級數(shù)據(jù)何時會被釋放,這意味著程序容易超過它的內(nèi)存限制并且崩潰畜侦。 自Android 3.0 (API Level 11)開始元扔, 像素級數(shù)據(jù)則是與Bitmap本身一起存放在Dalvik堆中

介于現(xiàn)在已經(jīng)minSdk至少在14以上了,所以接下來就不討論手動回收的問題旋膳;

BitMap在到底占多大澎语?

  • 在android 中其實是可以通過api方法來調(diào)用獲取BitMap大小的

    public final int getByteCount() {
      // int result permits bitmaps up to 46,340 x 46,340
      return getRowBytes() * getHeight();
    }
    
    

    舉個栗子在nexus 5x上一張xxhdpi下512*512大小的PNG圖片所生成的BitMap 占用大小是802816 在xxxhdpi下占用內(nèi)存是451584 至于怎么算的具體請看http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=498 這個鏈接有詳細(xì)解答,涉及到一些native c代碼的跟蹤,還是值得學(xué)習(xí)一下擅羞; 那么在nexus 5x 上的density 是420(為什么不是480 不是號稱是1920X1080?)在xxhdpi上應(yīng)該是這么算的

    512/480 * 420 * 512/480 * 420 * 4 = 802816
    
    

    計算的過程會有精度丟失尸变,我覺得可以忽略不計算了,在BitMapFactory.cpp中有這么一個計算規(guī)則

    scaledWidth = int(scaledWidth * scale + 0.5f);
    scaledHeight = int(scaledHeight * scale + 0.5f);
    
    

至于為什么會乘以4,那就看源碼吧:

static const uint8_t gSize[] = {
    0,  // Unknown
    1,  // Alpha_8
    2,  // RGB_565
    2,  // ARGB_4444
    4,  // RGBA_8888
    4,  // BGRA_8888
    1,  // kIndex_8
  };

小結(jié)

BitMap 的大小涉及到的因素有:

  • 轉(zhuǎn)換色彩的格式是RGB_565 還是ARGB_888等减俏;

  • 所存放資源文件的draweble資源目錄召烂;

  • 機器本身的像素密度,密度越大娃承,所占內(nèi)存越大奏夫;

防止她紅杏出墻(OOM)

BitMap內(nèi)存管理

防止BitMap OOM 就應(yīng)該先了解系統(tǒng)對BitMap的管理,請移駕到:

將oom 降低到最小發(fā)生幾率

由于android以及第三方手機廠商平臺的差異化历筝,oom永遠(yuǎn)都會是crash上的承镏纾客;

圖片加載的問題目前開源社區(qū)有了很多優(yōu)秀的depends,例如:fresco ,picaso, glide 梳猪。我個人不建議自己從零開始造輪子寫加載庫麻削,但是可以去查看他們的源碼,學(xué)習(xí)他的實現(xiàn)方式春弥;

如果很不幸呛哟,App中會隔三差五來個OOM 那個不要慌張:

  • 操作BitMapFactory

BitmapFactory.Options提供一些附加屬性來指定decode的選項,解析Bitmap時用到2個重要參數(shù): 1.inJustDecodeBounds 設(shè)置為true后匿沛,decode方法解析Bitmap時會返回一個null扫责,只講這個圖片的原始大小(單位是像素)存入BitmapFactory.Options對象的options.outHeight和options.outWidth中俺祠,這樣可以在不分配內(nèi)存的情況下得到圖片的尺寸信息公给。 2.inSampleSize 這個參數(shù)代表縮小比例,如果是1蜘渣,代表原始尺寸淌铐,如果>1,假設(shè)為2,則縮小后圖片像素值為原圖的1/4(長1/2蔫缸,寬1/2)腿准,同等格式下,占用內(nèi)存也變?yōu)樵瓉淼?/4拾碌。decoder以2的冪作為系數(shù)吐葱,接近2的冪的數(shù)值都會被處理為最接近的2的冪值,3.4~4校翔,2.1~2弟跑,這樣。

縮小比例值


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 halfHeight = height / 2;  
        final int halfWidth = width / 2;  

        while ((halfHeight / inSampleSize) > reqHeight  
                && (halfWidth / inSampleSize) > reqWidth) {  
            inSampleSize *= 2;  
        }  
    }  

    return inSampleSize;  
}

在調(diào)用以上方法前防症,記得設(shè)置options.inJustDecodeBounds = true; 調(diào)用后算出比例后孟辑,則調(diào)用BitmapFactory.decodexxxx(res, resId, options);

舉個栗子

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);  

    options.inJustDecodeBounds = false;  
    return BitmapFactory.decodeResource(res, resId, options);  
}

就可以mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

  • 如果非常不幸的是你要操作(緩存)很多BitMap實例(這是有多糟糕)那么請用LruCache;LruCache 采用Lru算法將BitMap用鏈表的方式存入緩存哎甲,可以有效的控制BitMap 大小
int cacheSize = 4 * 1024 * 1024; // 4MiB 一般是可用內(nèi)存的1/8
LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) {
    protected int sizeOf(String key, Bitmap value) {
        return value.getByteCount();
    }
}

  • 簡單粗暴--捕捉錯誤 其實從根源上來說這不是解決OOM的辦法,這是一個不是辦法的辦法饲嗽,可以有效規(guī)避程序的崩潰炭玫,從而不至于嚴(yán)重影響程序的崩潰;

    try {
       ......
    } catch (OutOfMemoryError e) {
        e.printStackTrace();
        ......
    }
    
    

    更詳細(xì)的Bitmap處理 [http://jayfeng.com/2016/03/22/Android-Bitmap%E9%9D%A2%E9%9D%A2%E8%A7%82/]

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末貌虾,一起剝皮案震驚了整個濱河市吞加,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌尽狠,老刑警劉巖衔憨,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異晚唇,居然都是意外死亡巫财,警方通過查閱死者的電腦和手機盗似,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門哩陕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人赫舒,你說我怎么就攤上這事悍及。” “怎么了接癌?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵心赶,是天一觀的道長。 經(jīng)常有香客問我缺猛,道長缨叫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任荔燎,我火速辦了婚禮耻姥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘有咨。我一直安慰自己琐簇,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布座享。 她就那樣靜靜地躺著婉商,像睡著了一般。 火紅的嫁衣襯著肌膚如雪渣叛。 梳的紋絲不亂的頭發(fā)上丈秩,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天,我揣著相機與錄音淳衙,去河邊找鬼蘑秽。 笑死挽唉,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的筷狼。 我是一名探鬼主播瓶籽,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼埂材!你這毒婦竟也來了塑顺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤俏险,失蹤者是張志新(化名)和其女友劉穎严拒,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體竖独,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡裤唠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了莹痢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片种蘸。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖竞膳,靈堂內(nèi)的尸體忽然破棺而出航瞭,到底是詐尸還是另有隱情,我是刑警寧澤坦辟,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布刊侯,位于F島的核電站,受9級特大地震影響锉走,放射性物質(zhì)發(fā)生泄漏滨彻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一挪蹭、第九天 我趴在偏房一處隱蔽的房頂上張望亭饵。 院中可真熱鬧,春花似錦嚣潜、人聲如沸冬骚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽只冻。三九已至,卻和暖如春计技,著一層夾襖步出監(jiān)牢的瞬間喜德,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工垮媒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留舍悯,地道東北人航棱。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像萌衬,于是被迫代替她去往敵國和親饮醇。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 堅持秕豫,成就了成功朴艰。 我還沒有成功,可是我已經(jīng)走在通往成功的路上混移,因為祠墅,為一件事,我在堅持歌径。 萬丈高樓從地起毁嗦,這個道...
    上山畝教育閱讀 559評論 0 2
  • 創(chuàng)業(yè)也好,做產(chǎn)品也好回铛,都要有一種門檻思維狗准,這種門檻思維包括了兩種相反的工作方向,一個減法勺届,一個是加法驶俊。 一種減法可...
  • 一胚膊、git與svn的區(qū)別 GIT不僅僅是個版本控制系統(tǒng),它也是個內(nèi)容管理系統(tǒng)(CMS),工作管理系統(tǒng)等想鹰。如果你是一...
    裝在殼子里的刺猬閱讀 841評論 0 0
  • 公公住院兩周紊婉,今日終于出院了,這兩周里我接過了公公婆婆平時手里的活兒_買菜做飯看孩子辑舷,以前從來沒有問過菜價喻犁,這...
    你今天怎么樣閱讀 485評論 0 0