使用超大圖片和加載大量圖片

當(dāng)使用超大的Bitmap圖片或加載大量圖片時(shí)很容易出現(xiàn)OOM(Out Of Memory)的現(xiàn)象
一般有兩種解決的方法:
1、使用超大的Bitmap圖片時(shí)采取壓縮圖片的方法
2、加載大量圖片時(shí)使用LruCache緩存

使用超大圖片

BitmapFactory.Options有個(gè)inJustDecodeBounds屬性,將inJustDecodeBounds設(shè)置為true時(shí),這樣就可以在不給圖片分配內(nèi)存時(shí)讀取圖片的基本信息,讀取并設(shè)置之后,再把該值改為false,然后再進(jìn)行圖片解析,這就是壓縮圖片的原理。

計(jì)算inSampleSize

圖片壓縮時(shí)高和寬都按inSampleSize比例進(jìn)行壓縮,比如inSampleSize為4時(shí)就表示高和寬都為原來(lái)的1/4,圖片整體壓縮到原來(lái)的1/16。

// 計(jì)算inSampleSize
public static int calculateInSampleSize(BitmapFactory.Options options,
                                        int reqWidth, int reqHeight) {
    // 源圖片的高度和寬度
    final int height = options.outHeight;
    final int width = options.outWidth;
    // inSampleSize不能小于1
    int inSampleSize = 1;
    // 源圖片的高或?qū)挻笥谝蟮?    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;
}
從資源中解析圖片
// 解析圖片
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
                                                     int reqWidth, int reqHeight) {
    // 第一次解析將inJustDecodeBounds設(shè)置為true,來(lái)獲取圖片大小
    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);
}

這里從資源中解析圖片,所以需要傳入Resources和圖片的資源id;另外我們希望將圖片壓縮成多少尺寸就需要傳入相應(yīng)的寬和高。

向ImageView中加載圖片
mImageView.setImageBitmap(
        decodeSampledBitmapFromResource(
                getResources(), R.drawable.image, 100, 100));

加載大量圖片

LruCache緩存主要算法原理是把最近使用的對(duì)象用強(qiáng)引用存儲(chǔ)在LinkedHashMap中,并且把最近最少使用的對(duì)象在緩存值即將達(dá)到預(yù)設(shè)定值之前從內(nèi)存中移除。

實(shí)例化緩存對(duì)象
// 每個(gè)應(yīng)用程序最高可用內(nèi)存,單位KB。
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024));

// 設(shè)置緩存空間的大小為可用最大內(nèi)存的1/8
int cacheSize = maxMemory / 8;

// 傳入緩存大小實(shí)例化緩存對(duì)象
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
    @Override
    protected int sizeOf(String key, Bitmap bitmap) {
        // 每張圖片的大小單位是KB
        return bitmap.getByteCount() / 1024;
    }
};
將圖片加入緩存
// 將圖片加入緩存
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
    if (getBitmapFromMemCache(key) == null) {
        mMemoryCache.put(key, bitmap);
    }
}
從緩存中獲取圖片
// 從緩存中獲取圖片
public Bitmap getBitmapFromMemCache(String key) {
    return mMemoryCache.get(key);
}
加載圖片的異步任務(wù)
// 加載圖片的異步任務(wù)
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {

    private ImageView imageView;

    public BitmapWorkerTask(ImageView imageView) {
        this.imageView = imageView;
    }

    // 在后臺(tái)加載圖片。
    @Override
    protected Bitmap doInBackground(Integer... params) {
        // 從資源中解析圖片
        final Bitmap bitmap = decodeSampledBitmapFromResource(
                getResources(), params[0], 100, 100);
        // 將圖片加入緩存
        addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);
        // 返回解析出來(lái)的圖片
        return bitmap;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        // 設(shè)置ImageView的圖片
        imageView.setImageBitmap(bitmap);
    }
}
加載圖片
// 加載圖片
public void loadBitmap(int resId, ImageView imageView) {
    // 將圖片資源id作為Key
    final String imageKey = String.valueOf(resId);
    // 從緩存中加載圖片
    final Bitmap bitmap = getBitmapFromMemCache(imageKey);
    // 如果緩存中有的話
    if (bitmap != null) {
        // 設(shè)置ImageView的圖片
        imageView.setImageBitmap(bitmap);
    } else {// 如果緩存中沒(méi)有
        imageView.setImageResource(R.drawable.image);
        // 傳入ImageView實(shí)例化加載圖片的異步任務(wù)
        BitmapWorkerTask task = new BitmapWorkerTask(imageView);
        // 開啟異步任務(wù)從資源中加載
        task.execute(resId);
    }
}

參考

Android高效加載大圖、多圖解決方案,有效避免程序OOM

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,363評(píng)論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,497評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,305評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,962評(píng)論 1 311
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,727評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,193評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,257評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,411評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,945評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,777評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,978評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,519評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,216評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,657評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,960評(píng)論 2 373

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

  • 寫在前面其實(shí)這篇文章也是很多圖片加載框架的基本原理。從本篇文章你將get到:1、如何計(jì)算一張圖片所占用的內(nèi)存大小2...
    LiveMoment閱讀 2,203評(píng)論 1 27
  • 在編寫Android程序的時(shí)候經(jīng)常要用到許多圖片,不同圖片總是會(huì)有不同的形狀、不同的大小,但在大多數(shù)情況下,這些圖...
    讀行游閱讀 1,288評(píng)論 2 12
  • 加載圖片 我們?cè)诰帉慉ndroid程序的時(shí)候經(jīng)常要用到許多圖片,不同圖片總是會(huì)有不同的形狀、不同的大小,但在大多數(shù)...
    badcyc閱讀 548評(píng)論 0 1
  • 高效加載大圖片 我們?cè)诰帉慉ndroid程序的時(shí)候經(jīng)常要用到許多圖片,不同圖片總是會(huì)有不同的形狀、不同的大小,但在...
    咸魚Jay閱讀 209評(píng)論 0 1
  • D57~4月19日 感恩神的管教。因?yàn)槌詵|西沒(méi)有節(jié)制,胃腸感冒了 感恩晚上遇到會(huì)針灸的姊妹,扎了幾針身體感覺(jué)舒服多...
    sky冬日暖洋洋閱讀 173評(píng)論 0 0