原因是: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: 量小的时候此方法简单实用,量大的时候还需要完善斟酌。