美文网首页Android技术知识Android开发经验谈Android程序猿
what?使用Handler也会引起的内存泄漏!!!

what?使用Handler也会引起的内存泄漏!!!

作者: 行者_zm | 来源:发表于2018-12-25 07:26 被阅读9次

说的挺吓人的,就一个Handler处理消息事件而已,怎么可能会出现内存泄漏的情况呢?说是内存泄漏,那到底如何发生内存泄漏的呢?又在哪里发生的内存泄漏?

在Android开发中,经常会在Activity中使用handler来进行线程间通信,使主线程能够实时更新UI但是,在Android Studio中,发现使用handler时会有黄色的警告提示。提示语为this Handler class should be static or leaks might occur。这条提示的内容就是说:使用handler可能会发生内存泄漏,建议改成静态的。那么为什么Activity中使用handle会存在内存泄漏的隐患呢?

1.当一个android应用程序启动的时候,frameworks会自动为这个应用程序在主线程创建一个Looper对象。这个被创建的Looper对象也有它主要的工作,它主要的工作就是不断地处理消息队列中的消息对象。在android应用程序中,所有主要的框架事件(例如Activity的生命周期方法,按钮的点击事件等等)都包含在消息对象里面,然后被添加到Looper要处理的消息队列中,主线程的Looper一直存在于整个应用程序的生命周期中。

2.当一个Handler在主线程中被初始化。那它就一直都和Looper的消息队列相关联着。当消息被发送到Looper关联的消息队列的时候,会持有一个Handler的引用,以便于当Looper处理消息的时候,框架可以调用Handler的handleMessage(Message msg)。

3.在java中,非静态的内部类和匿名内部类都会隐式的持有一个外部类的引用。静态内部类则不会持有外部类的引用。

下面我们举个例子:

在我们开发程序的时候,通常会写出如下代码:

 private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg){
            //执行
        }
    };

上面的代码是会产生内存泄漏的,你用测试工具,或者Android Studio会有提示

不过上面的代码不是特别容易发现问题,下面我们在来看这块代码,可能就会发现问题了:

public class MainActivity extends AppCompatActivity {

        private Handler mLeakHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //发送延时消息
        mLeakHandler.postDelayed(new Runnable() {
            @Override
            public void run() {

            }
        }, 1000 *60 *10);
        finish();
        }
    }

我们看上面的代码会发现,当Activity被finished掉的时候,被延时的消息会在被处理之前存在于主线程的消息队列中十分钟,而这个消息中又包含了Handler的引用,而Handler是一个匿名内部类的实例,其持有外面的MainActivity的引用。这些引用会一直保持到该消息被处理,从而阻止了MainActivity被垃圾回收器回收。因此这就导致了MainActivity无法被回收,进而导致MainActivity持有的很多资源都无法回收,这就是我们常说的内存泄漏。

发现了问题了,那我们如何解决呢?请往下看、

解决办法

要解决这样的一个问题,有如下几种方式:

1.最直接的思路就是避免使用非静态内部类。使用Handler的时候,放在一个新建的文件中来继承Handler或者使用静态的内部类来替代。静态内部类不会隐含的持有外部类的引用,因此这个activity也就不会出现内存泄漏问题。

2.如果你需要在Handler内部调用外部Activity的方法,你可以让这个Handler持有这个Activity的弱引用,这样便不会出现内存泄漏的问题了。

3.另外,对于匿名类Runnable,我们同样可以设置成静态的,因为静态内部类不会持有外部类的引用。

4.注意:如果使用Handler发送循环消息,最好是在Activity的OnDestroy方法中调用mLeakHandler.removeCallbacksAndMessages(null);移除消息。(这不是解决内存泄漏的方法)

使用弱引用(WeakReference):
public class SampleActivity extends AppCompatActivity {

  /**
   * Instances of static inner classes do not hold an implicit
   * reference to their outer class.
   * 弱引用的方式
   */
    private static class MyHandler extends Handler {
    
    private final WeakReference<SampleActivity> mActivity;
    
    public MyHandler(SampleActivity activity) {
      mActivity = new WeakReference<SampleActivity>(activity);
    }

    @Override
    public void handleMessage(Message msg) {
      SampleActivity activity = mActivity.get();
      if (activity != null) {
         //to Something
      }
    }
 }

使用静态方法:
//定义成static的,因为静态内部类不会持有外部类的引用
  private final MyHandler mHandler = new MyHandler(this);
  private static final Runnable sRunnable = new Runnable() {
      @Override
      public void run() {//to something}
  };

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mHandler.postDelayed(sRunnable, 1000 * 60 * 10);
    finish();
  }
}

总结

其实android中出现的大部分的内存泄漏都是Activity使用非静态内部类导致的,所以我们在使用内部类的时候要格外注意,如果其持有的引用超过了生命周期的范围,就极有可能会出现内存泄漏。以上的几种方式,由个人喜好来决定。

相关文章

  • what?使用Handler也会引起的内存泄漏!!!

    说的挺吓人的,就一个Handler处理消息事件而已,怎么可能会出现内存泄漏的情况呢?说是内存泄漏,那到底如何发生内...

  • java基础

    Handler怎样防止内存泄漏 handler引起内存泄漏的原因:由于handler的写法问题,如果handler...

  • Handler

    一,什么是handler 二,handler的使用 三,handler机制原理 四,handler引起的内存泄漏和...

  • 安卓日记Handler的内存泄漏

    Handler大家都在用,用来线程的通信,实现异步间的信息传递handler有个小坑 不优化的话 会引起内存泄漏要...

  • 重谈Handler的内存泄漏

    Handler 的内存泄漏问题 在多线程操作中,handler会使用的非常多,但是每次使用handler你有没有考...

  • 重谈Handler的内存泄漏

    Handler 的内存泄漏问题 在多线程操作中,handler会使用的非常多,但是每次使用handler你有没有考...

  • Android Handler 内存泄漏分析&解决方案

    一、前言 我们在开发过程中,经常使用 Handler,而使用 Handler 很容易造成内存泄漏,Android ...

  • Android的垃圾回收与内存泄露

    标签(空格分隔): Android 内存泄漏的基本知识请见博客一如何高效使用handler避免内存泄漏请见博客二 ...

  • EditText延迟搜索

    使用Handler的延迟发送实现: 一般使用Handler会有一个内存泄漏的提示: 可以使用WeakReferen...

  • Handler的正确使用,防止内存泄漏

    如果Handler使用不当,会导致内存泄漏,直至内存溢出。因此,为了避免这种情况的发生,Handler要定义为st...

网友评论

    本文标题:what?使用Handler也会引起的内存泄漏!!!

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