原因是: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: 量小的時候此方法簡單實用,量大的時候還需要完善斟酌。