使用setBackgroundResource、setBackgroundDrawable或者setBitmapDrawable多次加載大圖導致oom

原因是:Drawable生成方法內部調用BitmapFactory.decodexxx方法解析成Bitmap,再通過new BitmapDrawable(xxx)方式生成了Drawable。在此過程中,頻繁的調用生成Bitmap方法就容易造成OOM。

 

解決辦法:新增工具類BitmapManagerUtils,內部靜態map保存生成過的bitmap,防止多次使用重複生成相同bitmap.

/**
 * to resolve oom when use setBackgroundResource with big image,
 * waring: need to remember to release bitmapDrawables' Map
 */

public class BitmapManagerUtils {
    private static Map<Integer,BitmapDrawable> bitmapDrawables = new HashMap<>();
    private Context mContext = null;

    public BitmapManagerUtils(Context context){
        mContext = context;
    }

    public void setBitmapDrawables(View view, int resId){
        BitmapDrawable bitmapDrawable = null;
        bitmapDrawable = findBitmapDrablesById(resId);
        if (bitmapDrawable == null){
            bitmapDrawable = readBitMap(mContext, resId);
            if (bitmapDrawables != null){
                bitmapDrawables.put(resId, bitmapDrawable);
            }
        }
        view.setBackground(bitmapDrawable);
    }

    private BitmapDrawable findBitmapDrablesById(int resId){
        if (bitmapDrawables != null && bitmapDrawables.size() > 0){
            return bitmapDrawables.get(resId);
        }
        return null;
    }

    /**
     * to resolve oom when use setBackgroundResource with big image
     * @param context
     * @param resId
     * @return
     */
    private BitmapDrawable readBitMap(Context context, int resId) {
        BitmapFactory.Options opt = new BitmapFactory.Options();
        opt.inPreferredConfig = Bitmap.Config.RGB_565;
        opt.inPurgeable = true;
        opt.inInputShareable = true;
        // load resource
        InputStream is = context.getResources().openRawResource(resId);
        Bitmap bitmap = null;
        BitmapDrawable bitmapDrawable = null;
        if (is != null){
            bitmap = BitmapFactory.decodeStream(is, null, opt);
            if (bitmap != null){
                bitmapDrawable = new BitmapDrawable(context.getResources(), bitmap);
            }
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bitmapDrawable;
    }

    public static void release(){
        if (bitmapDrawables != null){
            bitmapDrawables.clear();
            bitmapDrawables = null;
        }
    }
}

使用方法:

1.使用

BitmapManagerUtils mBitmapManagerUtils = new BitmapManagerUtils(this);

mBitmapManagerUtils.setBitmapDrawables(view, resId);

2.釋放

在activity 銷燬時釋放對bitmap引用,然後手動gc:

 @Override
    protected void onDestroy(){
        super.onDestroy();
        if (view != null)
        view.setBackgroundResource(0);
        System.gc();
    }

並且在結束不再使用的時候,例如退出app或者功能模塊的時候,調用BitmapManagerUtils.release()釋放靜態map:

private void quit(){
    AppManager.getAppManager().finishAllActivity();
    BitmapManagerUtils.release();
}

PS: 量小的時候此方法簡單實用,量大的時候還需要完善斟酌。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章