Android多线程:Handler类应该是静态的,否则可能会发生内存泄漏。

6

我正在使用一个handler对象,在一个单独的线程中完成一个耗时的任务后,继续UI工作。以上Lint警告的问题,以下是我的解决方法。

[ 示例Handler对象类型1 ] ->

Handler responseHandler = new Handler()
{
    @Override
    public void handleMessage(Message msg)
    {
        super.handleMessage(msg);
        Toast.makeText(MainActivity.this, "Finished the long running task in seperate thread...", Toast.LENGTH_LONG).show();
    }       
};
[示例处理程序对象类型2] ->
Handler responseHandler = new Handler(new Handler.Callback() 
{       
    @Override
    public boolean handleMessage(Message msg) 
    {   
        Toast.makeText(MainActivity.this, "Finished long running task in a seperate thread...", Toast.LENGTH_LONG).show();
        return false;      // RETURN VALUE ????
    }
});

在除了UI线程之外的另一条线程中,当耗时任务完成后,它会执行以下代码行以将控制权返回到UI线程(基本上是返回到处理程序对象)。
responseHandler.sendEmptyMessage(0);

该程序使用两种类型的handler对象都可以正常工作,但是在使用第一种类型时,会出现一个Lint警告:此Handler类应该为静态的,否则可能会出现泄漏。因此我开始使用第二种类型的handler对象来避免这个Lint警告,但问题是,我不确定第二种方式中返回值(true/false)的含义,并且它能够处理任意一种情况。我在谷歌上搜索了很多,但没有得到确切的答案来解释这个返回值。在stackoverflow的许多地方看到这个问题被问及,主要涉及到Lint警告,但我的问题主要是关于第二种方法中的返回类型,以及确认使用第二种类型的handler对象是否正确解决了问题。
问题如下:
1). 有人知道这个返回值(true/false)的确切含义吗?
2). 我用第二种handler对象来消除Lint警告是正确的吗?
谢谢...

是的,操作员请检查链接的帖子。 - Ivan Bartsov
我看到了这些链接,我的问题主要是关于返回值,在那里我没有找到解释。 - JibW
请查看以下内容:https://dev59.com/r3TYa4cB1Zd3GeqP0_lE#17899429。并参考这篇文章:https://groups.google.com/forum/#!topic/android-developers/1aPZXZG6kWk,以获取有关该主题的讨论和romain guy提供的解决方案。 - Raghunandan
2个回答

5
每个处理器都绑定到线程的 Looper 上,每个 Message 都会被放置在一个数据结构,即消息队列中。
Message 有一个 target 变量指向 Handler,还有一个 callback 变量指向 Runnable。
因此,如果您正在使用匿名类创建 Handler 对象(例如第一个示例中),则应知道匿名/非静态内部类具有对外部对象(Activity?)的引用。因此,在队列上发布的消息可能会引用 Handler 作为目标,并且 Handler 反过来又引用了外部类,比如 Activity。
现在,一条消息可以在消息队列中停留很长时间,只要线程在运行。同时,活动可能已经被销毁。但是,由于该消息拥有的模糊间接引用关系,它不会被垃圾回收。请注意,只要线程在运行,Looper 和 Message Queue 就会一直存在。
在第二个示例中,您并没有创建匿名 Handler 类。相反,您使用了处理器构造函数并传递了一个匿名回调对象。这可能会使 Lint 不再抱怨,但我怀疑这是否是一个好方法。只需避免使用内部类,避免将 Activity 或上下文引用传递给 Handler。
更新:
Handler 的 dispatchMessage() 获取要处理的消息,检查是否提供了回调。如果提供了回调,则不调用 handleMessage(),如果回调的 handleMessage() 返回 true:
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg); //--won't be called if you return true.
    }
}

1

我发现一些关于内部类(如handler)引起的内存泄漏的重要信息,想和你分享:

如何泄露context:Handlers & Inner Classes 而且我认为Handler类的重写方法不会返回任何东西,你可以检查一下: handleMessage()

你重写了Java Handler类而不是Android Handler类。你可以看到Java Handler类的handleMessage()有一个返回语句,你可以在这里查看返回语句的原因:boolean handleMessage(C context)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接