【问题标题】:Why Handler leak issue won't happen in thread other than the main thread为什么处理程序泄漏问题不会在主线程以外的线程中发生
【发布时间】:2016-04-23 09:23:31
【问题描述】:

我的活动代码如下

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

Android Studio lint:

处理程序引用泄漏

由于这个 Handler 被声明为一个内部类,它可能会阻止外部类被垃圾回收。 如果 Handler 在主线程以外的线程使用 Looper 或 MessageQueue,则没有问题。 如果 Handler 使用主线程的 Looper 或 MessageQueue,则需要修复Handler声明,如下:将Handler声明为静态类;在外部类中,实例化一个WeakReference给外部类,在你实例化Handler的时候把这个对象传给你的Handler;使用 Wea​​kReference 对象对外部类的成员进行所有引用。

我知道 Handler 引用泄漏是因为它持有 Activity 的强引用,而 Activity 不能被垃圾回收器回收,但是为什么 Handler 泄漏问题不会发生在主线程以外的线程中呢?主线程生命周期与应用程序一样长?

【问题讨论】:

  • 你发现了吗?因为三年后我也有同样的问题。

标签: android


【解决方案1】:

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

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

所以我的理解是,在上述情况下,这个警告并不完全正确。或者,也许我错过了一些东西。

您可以争辩说,一旦调用 Activity.onDestroy,这个线程就可以终止,这当然可以防止这里的引用泄漏。

【讨论】:

    【解决方案2】:

    Android Studio lint 提到了 Handlerinside Looper 或 MessageQueue。 来自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();
      }
    }
    

    这显然不包含对任何 Activity 的引用,因此没有泄漏。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-23
      • 2011-11-08
      • 2018-12-18
      相关资源
      最近更新 更多