我应该在销毁活动时手动关闭我的应用程序创建的 HandlerThreads 吗?

Posted

技术标签:

【中文标题】我应该在销毁活动时手动关闭我的应用程序创建的 HandlerThreads 吗?【英文标题】:Should I manually close HandlerThreads created by my application when destroying the activity? 【发布时间】:2013-02-02 15:35:01 【问题描述】:

我的应用由单个 Activity 组成。在此活动中,我创建了多个 HandlerThreads,它们在循环中运行以执行套接字阻塞操作。

目前,我在Activity.onDestroy() 期间向这些HandlerThread中的每个人发布了一条退出消息。

有时,当我打开我的应用程序,关闭它并重新启动它时,它会崩溃(很多时候是由于将消息发布到未运行的处理程序线程)。

我的问题是:当我关闭我的应用程序时,关闭 HandlerThread 的正确方法是什么?(请注意,这些线程可能会阻塞套接字操作)。

编辑:更多信息: 我有一个在 onCreate 中启动的处理程序线程池(当我第一次启动我的应用程序时没问题)。

每个处理程序可运行循环都用一个

包装
 if (shouldRun) 
//body
 
else  
 close();

声明。

close 方法删除所有待处理的消息和可运行的消息,并向处理程序发布一条消息,这将导致他调用其looper.quit()。 这样,如果当前的处理线程被 IO 操作阻塞,只有当它完成它才会退出()。

【问题讨论】:

请分析崩溃原因。也许真正的原因是你的 HandlerThread 对象试图向 Activity 发布一些死掉的东西不再存在。您需要通知仍在运行的线程它们丢失了上下文。 【参考方案1】:

是的,最好关闭它。还要确保删除您的回调。

@Override
public void onDestroy() 
    super.onDestroy();
    handler.removeCallbacksAndMessages(null);
    handler.getLooper().quit();

【讨论】:

但是当我重新启动我的应用程序时,我遇到了那些崩溃。我已经尝试了扩展答案。 你是否在重新启动时创建一个新的处理程序/线程并再次调用 Looper.prepare()/Looper.loop()? 据我了解,@Daniel 具有等待阻塞 I/O 操作的 HandlerThread 对象。要求 Looper 退出()不会立即生效。【参考方案2】: 你必须有一些不一致的地方,否则你的应用程序不会崩溃。你确定一个没有运行的 HandlerThread 真的是原因吗?创建 Activity 时不创建 HandlerThread 对象吗? 如果您的 HandlerThreads 正在等待 I/O 操作,我会考虑尝试中断它们。简单地删除回调和消息并要求 Looper 退出,甚至向 Handler 发送终止消息,都不会做任何事情。 HandlerThread 对象仍然存在,直到 android 终止进程(可能会发生也可能不会发生)。这意味着“您的应用程序将收集可能无法访问的僵尸 HandlerThread 对象”。当然,除非您可以向这些 HandlerThreads 发送一条终止消息,该消息到达它们阻塞的通道。 重用 HandlerThread 对象会更好。服务可能是执行此操作的正确模型。 此外,如果线程在您的 Activity 中存活,您需要通知它们它们的通信对等方(您的 Activity)已消失。否则,它们可能指的是已经消失的东西。

【讨论】:

请使用堆栈跟踪发布异常。此外,核心问题是,您的 HandlerThread 对象是否维护对 Activity 的引用。【参考方案3】:
    /**
 * Ask the currently running looper to quit.  If the thread has not
 * been started or has finished (that is if @link #getLooper returns
 * null), then false is returned.  Otherwise the looper is asked to
 * quit and true is returned.
 */
public boolean quit() 
    Looper looper = getLooper();
    if (looper != null) 
        looper.quit();
        return true;
    
    return false;

以上是HandlerThread.java源码的'quit'方法,直接调用即可。

为什么要叫quit?下面是HandlerThread.java源码的'run'方法。

    public void run() 
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) 
        mLooper = Looper.myLooper();
        notifyAll();
    
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();//always loop except for a Message with null target

    mTid = -1;

答案是'循环是一个'while(true)'方法,它会返回直到收到一个目标为空的消息。

【讨论】:

【参考方案4】:

最佳实践方法是在活动onDestroy() 中删除对处理程序的回调。有关更多信息,请参阅此答案:

https://***.com/a/5038542/1369222

【讨论】:

【参考方案5】:

当 Looper 退出时,HandlerThread 会停止。 HandlerThread.getLooper().quit() 当你停止你的活动时。 (请参阅http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1.1/android/app/IntentService.java#IntentService.ServiceHandler.%3Cinit%3E%28android.os.Looper%29 以获得正确使用 HandlerThread 的一个很好的示例)

【讨论】:

据我了解,@Daniel 具有等待阻塞 I/O 操作的 HandlerThread 对象。要求 Looper 退出()不会立即生效。 可能,是的。在这种情况下,handlerThread.interrupt() 应该停止这些操作(但这并不特定于 HandlerThread)

以上是关于我应该在销毁活动时手动关闭我的应用程序创建的 HandlerThreads 吗?的主要内容,如果未能解决你的问题,请参考以下文章

当实际的活动名称节点关闭时,HDFS HA 集群备用节点不会变为活动状态

我啥时候应该销毁令牌[关闭]

在活动被销毁后运行Bindservice

在JSP中销毁会话[关闭]

释放elasticsearch连接

当Activity被销毁时,为什么Service会破坏自我?