在项目中要使用几十张图片,以及背景,产生了out of memory异常.
Bitmap bitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), gi.getBitMapResoureceId(), mOptions));
因为大量使用图片而且切换屏幕时或回到前台时重复生成Bitmap ,导致内存溢出。
专门针对out of memory进行了调查。
问题点:
a.使用大量图片,耗用内存和cup
b.横竖屏切换或者activity回到前台时重复的调用了一些代码,例如读取数据库,重复生成一些对象
c.由于组件的背景图片多,在频繁横竖屏切换时重新加载xml会一时间占用大量内存
方法:
1.提取重复性的代码,就是能一次在onCreate()中做好的东西,不要再onResume()和onConfigurationChanged()中重复出现,这个要考虑业务和逻辑的东西。
但是组件和Layout还是要在onConfigurationChanged()重新加载的(我们使用了android:configChanges="touchscreen|keyboardHidden|orientation",所以横竖屏切换时只调用onConfigurationChanged()方法)。
2.将app的背景图片和button的背景及src从xml中提取出来,在代码中设置为成员变量,一次性读入不再重复读取
例如:
xml中:
android:background="@drawable/bg"
android:src="@drawable/water"
Java代码中:
private Drawable mBgDrawable = getResources().getDrawable(R.drawable.bg);
private Drawable mWaterDrawable = getResources().getDrawable(R.drawable.waterbg);
RelativeLayout mMainLayout = (RelativeLayout) findViewById(R.id.main);
ImageButton mBtnWater = (ImageButton ) findViewById(R.id.waterbyn);
mMainLayout.setBackgroundDrawable(mBgDrawable );
mBtnWater .setImageDrawable(mWaterDrawable );
ImageButton 设置时也可以是setBackgroundDrawable那这样就和xml中的background一个效果了。
后来又把这些成员变量做出static的,是为了提高效率。
但后来发现了问题。就是网上很多的关于Drawable会使用setCallback保留对组件(ImageButton )的引用,而组件又会保留对activity的引用,这样activity上的计数器不会0,虚拟机也不能回收已经不用的activity对象,再次引发内存溢出。
setBackgroundDrawable:
这里面的d.setCallback(this)可能会导致保留对组件的引用。当重新调用setBackgroundDrawable时,Drawable调用mBGDrawable.setCallback(null)先将原来的引用设置为null。
回到我的项目,我们在切换横竖屏时并没有重新生成activity,也没有需要销毁的activity,而且最初我们没有设置为static,那么这些成员变量的生命周期和activity是相同的,不会引发上述问题。(理论推测)我们目前的做法是在onConfigurationChanged()中增加了这么句话:
mWaterDrawable .setCallback(null)做个双保险。
那当将Drawable的变量设置为static后,应该在onDestroy中也调用mWaterDrawable .setCallback(null),保证activity可以被正常回收。
继续跟进中……