美文网首页
非静态内部类Handler类引起内存泄露

非静态内部类Handler类引起内存泄露

作者: 程序员学园 | 来源:发表于2017-04-04 01:01 被阅读0次

最近在项目中使用延时Handler做Splish页面的跳转。


new Handler().postDelayed(new Runnable() {
       @Override
       public void run() {
       Intent intent = new Intent(SplishActivity.this,MainActivity.class);
       startActivity(intent);
       finish();
    }
},100);

谁知道产生如下内存泄露。

static android.app.Instrumentation.mRecommendActivity

referencs android.app.Instrumentation$RecommendActivity.mTarget

leaks XXX.SplishActivity instance
8D922718668811AB9F21445AB0017F90.jpg

仔细一想确实是这么回事,因为可能延时Handler还没处理消息,页面就finish了,但是因为Handler是非静态内部内,会持有外部Activity的引用,所以导致外部Activity不能被销毁,故而产生内存泄露。

所以为了安全起见,把Handler改为静态内部类,并且持有弱引用。

 private Handler mHandler = new MyHandler(this);
    private static class MyHandler extends Handler{
        private final WeakReference<Activity> mActivity;
        public MyHandler(Activity activity) {
            mActivity = new WeakReference<Activity>(activity);
        }
        @Override
        public void handleMessage(Message msg) {
            System.out.println(msg);
            if(mActivity.get() == null) {
                return;
            }
        }
    }
    private Runnable mRunable = new Runnable() {
        @Override
        public void run() {
            Intent intent = new Intent(SplishActivity.this,MainActivity.class);
            startActivity(intent);
            finish();
        }
    };

mHandler.postDelayed(mRunable,100);
  @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacks(mRunable);
    }

总结内部Handler类引起内存泄露的原因

1、当Android应用启动的时候,会先创建一个应用主线程的Looper对象,Looper实现了一个简单的消息队列,一个一个的处理里面的Message对象。主线程Looper对象在整个应用生命周期中存在。

2、当在主线程中初始化Handler时,该Handler和Looper的消息队列关联。发送到消息队列的Message会引用发送该消息的Handler对象,这样系统可以调用 Handler#handleMessage(Message) 来分发处理该消息。

3、在Java中,非静态(匿名)内部类会引用外部类对象。而静态内部类不会引用外部类对象。
如果外部类是Activity,则会引起Activity泄露

4、当Activity finish后,延时消息会继续存在主线程消息队列中,然后处理消息。而该消息引用了Activity的Handler对象,然后这个Handler又引用了这个Activity。这些引用对象会保持到该消息被处理完,这样就导致该Activity对象无法被回收,从而导致了上面说的 Activity泄露。

5、要修改该问题,只需要按照Lint提示的那样,把Handler类定义为静态即可,然后通过WeakReference 来保持外部的Activity对象。

更正一下

上面

mHandler.postDelayed(mRunable,100);

上面用mRunable还是提示内存泄露。

改成sendMessageDelayed

 mHandler.sendMessageDelayed(Message.obtain(), 100);

相关文章

  • 非静态内部类Handler类引起内存泄露

    最近在项目中使用延时Handler做Splish页面的跳转。 谁知道产生如下内存泄露。 仔细一想确实是这么回事,因...

  • Android常见内存泄漏

    内存泄漏场景: 静态变量引用非静态内部类/匿名类实例。子线程相关的非静态内部类/匿名内部类引用。Handler导致...

  • Android面试:为什么Handler容易造成内存泄露?

    非静态内部类造成的内存泄露 原因:非静态内部类会持有外部类对象的引用。 结合代码及Profiler查看内存泄露情况...

  • 使用Handler导致内存泄露的解决方案

    常说Android的Handler非静态内部类持有外部Activity的引用会造成内存泄露 原因是究竟什么? 1)...

  • Android性能-内存泄漏

    泄漏原因: 单例造成的内存泄漏 非静态内部类(匿名类等)创建静态实例造成的内存泄漏 Handler/Thread/...

  • 内存泄漏实战总结

    一.handler造成内存泄漏: 非静态内部类会持有外部类的引用,handler的message的target持有...

  • 关于静态内部类

    静态内部类与非静态内部类的区别 非静态内部类会隐式持有外部类的引用,可能引起内存泄漏。 静态内部类只能调用外部类的...

  • Android 知识点 集锦

    1.自定义Handler时如何避免内存泄露 一般非静态内部类持有外部类的引用的情况下,造成外部类在使用完成后不能被...

  • 从源码角度看Handler为何会发生内存泄露

    首先我们看最常见的handler写法: 为什么handler会导致内存泄露呢?是因为内部类持有了外部类的引用引起的...

  • Android常见内存泄漏汇总

    目录:一、内存泄漏介绍二、常见内存泄漏场景1.单例导致内存泄露2.静态变量导致内存泄漏3.非静态内部类导致内存泄露...

网友评论

      本文标题:非静态内部类Handler类引起内存泄露

      本文链接:https://www.haomeiwen.com/subject/uqhaottx.html