Android 程序页面之间多次跳转照成手机内存飙高从而引发OOM的解决方案 初稿

先简单说下这个问题是怎么来的吧,程序打开进入主页,这个时候就可以通过主页来跳转到其他页面,有的是Activity或者是Fragment构建的页面,这个时候我们就可以通过Android Studio提供的Android Monitor观察Monitors中的Memory实时展示当前程序运行占用的内存,根据页面的复杂程度占用的内存高低不一,简单的就几MB,复杂的都是20MB/50MB,你以为这就结束了,呵呵!还没完,现在我们需要回到主页或者上一个页面,很简单直接调用下finish这时我们需要盯着Memory看看内存的占用情况,理论上当我们结束一个页面,被结束的页面应该立刻被GC才对,但实际上关闭的页面占用的内存并没有被释放掉,久而久之当用户在无规则的进行页面之间的跳转时,系统分配的内存很容易被占满从而照成程序闪退,说了这么多废话就是在为下面的解决方案做铺垫,现在直接上方案。

第一步:
在每个页面都调用onDestory(),当页面结束时在onDestory中释放掉实例出来的参数。例如:

public class XxxActivity extends Activity {
    priavte TextView textView = null; // 文本控件
    // 这里顺便一起把adapter的释放也一起演示了
    private RecyclerView xxx_rv; 
    private XxxAdapter xxxAdapter;
    private XxxUtils xxxUtils = new XxxUtils(); // 实例化出来的外部类
    private XxxHandle handle = new XxxHandle(this); // 为了避免Handle造成的内存泄露,我们需要优化写法,下面有例子
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.xxxx);
        textView = (TextView)findViewById(R.id.xxx);
        xxx_rv = (RecyclerView) findViewById(R.id.xxx);
        /**
        * 这里有必要说下,我看网上很多同学都遇到的
        * RecyclerView: No adapter attached; skipping layout 这个问题,网上也有客官老爷没给出了自己的解决方案,但大多都只能解决自己遇到的问题,我这次说不定也是一样,反正分享出来
        * 出现这个异常,程序是不会蹦掉的,但是如果有处女情结的同学可能就会焦虑好久,我是这样解决这个问题的,在onCreate中初始好Adapter和RecyclerView,Adapter中数据传入单独写个方法(下面会给出例子),如果Adapter中onBindViewHolder里写好了数据展示,就先做个非空判断,这时只要我们的数据解析完成了,就将数据传入然后调用notifyDataSetChanged()刷新Adapter,这样logcat中就不会出现这个异常提示了
        */
        xxxAdapter = new XxxAdapter();
    }

/**
* 避免Handle泄漏优化写法
*/
private static class XxxHandle extends Handler {
        private WeakReference<Context> reference;
        XxxHandle(Context context) {
            reference = new WeakReference<>(context);
        }
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            XxxActivity m = (XxxActivity) reference.get();
            switch (msg.what) {
                case xxx: {
                    m.xxx(msg.obj);
                    break;
                }
            }
        }
    }

     @Override
    public void onDestroy() {
        // 释放Handle
        handle.removeCallbacksAndMessages(null);
        handle = null;
        // 释放Adapter
        xxx_rv.setAdapter(null);
        xxx_rv.setAdapter(xxxAdapter); 
        xxx_rv = null;
        // 释放文本控件
        textView = null// 释放实例的外部类
        xxxUtils = null// 这里是我看网上有位同学给出的方案,有效果但也不大,view_null.xml是一个没有控件的空layout
        setContentView(R.layout.view_null);
        super.onDestroy();
    }
}

第二步:
加入Leakcanary来检查内存泄漏问题。用法:
1. 在build.gradle中加入引用

dependencies {
   debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'
    releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'
 }

2.在 Application中初始化调用

    public static RefWatcher getRefWatcher(Context context) {
        XxxApplication application = (XxxApplication) context
                .getApplicationContext();
        return application.refWatcher;
    }

    private RefWatcher refWatcher;

    @Override
    public void onCreate() {
        super.onCreate();
        refWatcher = LeakCanary.install(this);
    }

3.最后在内存占用比较多的页面中的onDestroy()里调用我们在Application中实例化的LeakCanary

    @Override 
    public void onDestroy() {
        super.onDestroy();
        RefWatcher refWatcher = XxxApplication.getRefWatcher(this);
        refWatcher.watch(this);
    }

这样就完成了Leakcanary的嵌入,当程序出现内存泄漏问题时会主动发推送到通知栏,然后就可以根据提示去手动优化了,Leakcanary还会去帮我们释放程序占用的内存。

总结:
完成以上步骤后,我们再来运行程序观察Memory的变化就会发现之前finish掉的页面内存没有被释放的情况被有效的解决了(例如首页启动占用了20MB,开启一个页面加载完成后内存上升到50MB,finish掉这个页面,过几秒内存就会降到20MB,可能会比原有多出几MB)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值