为什么Handler泄漏问题不会在主线程以外的线程中发生

时间:2016-01-18 09:03:30

标签: android

我的活动代码如下

Handler handler = new Handler(){
        @Override
        public void dispatchMessage(Message msg) {
            super.dispatchMessage(msg);
        }
    };

Android Studio lint:

  

处理程序引用泄漏

     

由于此Handler被声明为内部类,因此可能会阻止外部类被垃圾回收。 如果Handler对主线程以外的线程使用Looper或MessageQueue,则没有问题。如果Handler正在使用主线程的Looper或MessageQueue,则需要修复处理程序声明如下:将Handler声明为静态类;在外部类中,实例化外部类的WeakReference,并在实例化Handler时将此对象传递给Handler;使用WeakReference对象对外部类的成员进行所有引用。

我知道Handler引用泄漏,因为它拥有强大的活动引用,并且活动无法通过垃圾收集来收集,但为什么Handler泄漏问题不会在主线程以外的线程中发生?主线程生命周期与应用程序一样重要吗?

2 个答案:

答案 0 :(得分:1)

如果查看Handler实现,那么您将看到最初它没有将自己的引用传递给任何外部(即Looper)对象。一旦您post收到消息,this引用被分配给消息target字段,它就会在其外部传递参考。现在,如果您的消息是长期存在的(它的发布时间较长),那么它可能比您的Activity生命周期长,从而导致资源泄漏。实际原因是主线程消息队列,它包含一个引用处理程序的消息,该处理程序还包含对您的活动的引用。当您的处理程序在您的活动中处于内部静态时,会发生此引用泄漏。

因此现在让我们将主线程消息队列替换为其他一些线程消息队列。因为这是此警告消息所说的内容。假设你的处理程序仍然是你的活动的内部静态,但它使用了一些其他线程的looper,假设你想要有一些延迟发布消息到这个线程。一旦你的延迟消息进入这个工作线程的消息队列,它仍然会导致引用泄漏 - 它将无限期地保留对你的处理程序的引用,这也会引用你的活动。

所以我的理解是,在上面的场景中,这种警告并不完全正确。或许我错过了一些东西。

你可以争辩说一旦调用了Activity.onDestroy就可以终止这个线程,这当然会阻止引用泄漏。

答案 1 :(得分:0)

Android Studio lint在 Looper或MessageQueue中讲述了Handler 。 来自Android docs的示例:

class LooperThread extends Thread {
  public Handler mHandler;

  public void run() {
      Looper.prepare();

      mHandler = new Handler() {
          public void handleMessage(Message msg) {
              // process incoming messages here
          }
      };

      Looper.loop();
  }
}

这显然没有任何活动的参考,因此没有泄漏。