又见图片导致的OOM
发生环境
1.在一个Activity中,多个View(Layout)进行来回的切换,使用一个Stack来作为页面栈,对view进行入栈(打开新页面,这时总是new一个View出来)和返回操作(出栈)。 2.每个view基本都继承了RelativeLayout,并在其xml布局中都添加了数目不少的自定义View控件(基本注册登录流程中的控件,像TextView、带下拉框的EditView,自定义Button、各种图片素材等)。 3.工程本身所占内存不少。 4.有多个Activity,报错的这部分在一个单独的Activity中(简称为A)
重现路径
在A中,多次点击跳转按钮,来回切换View,重复几次之后,应用重启。
崩溃现象
首先,Devices中,模拟器进程几乎一下子减少了一半,之后再进行页面跳转操作,就会发生应用崩溃后再重启的现象
Logcat
在日志中,首先是有OOM的提示,出来一堆指示当前进程的内存占用情况,之后是好多进程逐个开始crash掉,同时出现的还有多个Service重启(包括系统Service和应用中的Service),最后当前Activity died掉。
解决方案
由于这个现象实在我进行ui适配之后发生的,所以基本可以判断,不是代码的问题,应该是添加了ui素材导致的。大概看了一下,修改的部分主要是添加了图片,修改了字体颜色、字体、背景色、和背景(主要是用xml写的)。所以,基本确认是由于图片的原因导致内存溢出。
如何解决呢?我在网上找到这篇关于android 使用bitmap的OOM心得和解决方案 博客作为参考,根据我的实际情况,做出如下的解决。
1.由于oom导致根本原因是图片占据了大量内存,直接原因是View频繁的创建,所以,这些View都需要实现这样的接口
interface IPageLifeCycle{
//应当在实例化之后,放置于viewGroup之前被调用
public void onForenground();
//应当在销毁之前,从当前显示的ViewGroup中移除时调用
public void onBackground();
//应当在当前对象不需要存在,置null时调用
public void onRemove();
}
2.在自定义View中,也使用了数量不少的图片,以及自定义了一些以reference作为参数类型的自定义属性,用来存放drawable对象,所以这些图片也许需要在不使用时进行必要的释放。实现如下接口
interface IPageLifeCycle{
//释放内存
public void releaseMemory();
}
3.在A中,回退页面时,当stack pop出来View之后,需要调用
(IPageLifeCycle)view.public void onBackground();
(IPageLifeCycle)view.public void onRemove();
view = null;
4.在自定义的View控件中实现 public void releaseMemory(){ //备注中的方法 }
4.在View的onRemove()方法中,释放本身的图片资源和其所有自定义控件的内存。 public void onRemove(){ (IPageLifeCycle).releaseMemory(); //备注中的方法 System.gc(); }
这样,每次pop了view,都会使得垃圾回收机制回收掉无用的、占据大量内存的资源。
备注
无论你是在xml中布局使用了:
android:background ,
还是在java代码中调用了:
setBackground(background);
setBackgroundDrawable(background)
setBackgroundResource(resid)的方式去设置了背景图片.
使用的时候,请调用一下对应的方法:
setBackgroundResource和android:background→setBackgroundResource(0);
setBackgroundDrawable(background)→ setBackgroundDrawable(null)
setBackground(background) → setBackground(null)