【问题标题】:Timertask or HandlerTimertask 或 Handler
【发布时间】:2013-12-18 06:46:58
【问题描述】:

假设我想每 10 秒执行一次操作,它不一定需要更新视图。

问题是:像这里这样将计时器与 timertask 一起使用是否更好(我的意思是更高效和有效):

final Handler handler = new Handler();

TimerTask timertask = new TimerTask() {
    @Override
    public void run() {
        handler.post(new Runnable() {
            public void run() {
               <some task>
            }
        });
    }
};
timer = new Timer();
timer.schedule(timertask, 0, 15000);
}

或者只是一个带有后延迟的处理程序

final Handler handler = new Handler(); 
final Runnable r = new Runnable()
{
    public void run() 
    {
        <some task>
    }
};
handler.postDelayed(r, 15000);

如果您能解释一下何时使用哪种方法以及为什么其中一种方法比另一种更有效(如果确实如此),我将不胜感激。

【问题讨论】:

  • 我读过很多关于 TimerTasks 异常行为的帖子。我的建议是避开它们并使用处理程序 / postDelayed 方法。
  • 我更喜欢 Handler-postDelay 方法 - 你有更多的控制权,你可以从内部安排它
  • 这里是Timer vs. Handler的一个很好的来源
  • TimerTask 是一个后台任务,所以你不能更新 UI。只是说...
  • 对于阅读本文的人:@Yousha Aleayoub 当然你可以使用处理程序。

标签: android performance timer handler timertask


【解决方案1】:

使用定时器有一些缺点

它只创建一个线程来执行任务,如果一个任务需要 运行时间太长,其他任务会受到影响。它不处理异常 任务和线程抛出的只是终止,这会影响其他 计划任务并且它们永远不会运行

复制自:

TimerTask vs Thread.sleep vs Handler postDelayed - most accurate to call function every N milliseconds?

【讨论】:

  • 那么对于一次性任务呢?听起来 Timer 可能会更好,因为您没有消息队列的开销?
  • 我想我们永远不会知道
【解决方案2】:

Handler 优于 TimerTask

Java TimerTask 和 Android Handler 都允许您在后台线程上安排延迟和重复的任务。然而,绝大多数文献推荐在 Android 中使用Handler 而不是TimerTask(参见herehereherehereherehere)。

一些已报告的 TimerTask 问题包括:

  • 无法更新 UI 线程
  • 内存泄漏
  • 不可靠(并不总是有效)
  • 长时间运行的任务可能会干扰下一个计划事件

示例

我见过的各种 Android 示例的最佳来源是Codepath。这是一个重复任务的Handler 示例。

// Create the Handler object (on the main thread by default)
Handler handler = new Handler();
// Define the code block to be executed
private Runnable runnableCode = new Runnable() {
    @Override
    public void run() {
      // Do something here on the main thread
      Log.d("Handlers", "Called on main thread");
      // Repeat this the same runnable code block again another 2 seconds
      handler.postDelayed(runnableCode, 2000);
    }
};
// Start the initial runnable task by posting through the handler
handler.post(runnableCode);

相关

【讨论】:

  • @Reek 不,GC 应该处理它。但是您需要注意发布的可运行文件以延迟执行。在上面的示例中,使用的 runnable 是一个内部类实例,因此包含对包含类(可能是一个活动)的隐式引用。 runnable 将保留在处理程序的关联循环器的消息队列中,直到它的下一个执行时间,这可能是在上下文无效并且可能泄漏包含的类实例之后。您可以在适当的时候使用mHandler.removeCallbacks(runnableCode) 清除此类引用(例如,onStop() 用于活动)。
  • 最好的推荐方式!!! (见这里、这里、这里、这里、这里和这里)。
  • 如果我想在 ViewModel 中使用它怎么办?不反对那里没有android东西的理想吗?
  • @desgraci,我没有使用 ViewModel,但从documentation 我只看到它说 ViewModel 不应访问视图层次结构或包含对 Activity 或 Fragment 的引用。一般来说,我没有看到任何禁止使用“Android 的东西”的东西。
  • 截至今天,这些参考资料对我来说已经过时,而且信息量不足以考虑。仅当您的代码编程不当时,列出的这 4 个缺点才是真实的。如果您想定期在后台运行某些东西并最终在某些条件适用的情况下在 UIThread 上运行某些东西,TimerTasks 仍然是一个非常好的选择。
【解决方案3】:

接受答案的 Kotlin 版本:

// execute on the main thread, empty constructor is deprecated
val handler = Handler(Looper.getMainLooper())

val runnableCode = object : Runnable {
    override fun run() {
        Log.d("Handlers", "Called on main thread")
        handler.postDelayed(this, 2000)
    }
}

// or shorter using a lambda function
val runnableCode = Runnable {
    Log.d("Handlers", "Called on main thread")
    handler.postDelayed(this, 2000)
}

handler.post(runnableCode)

【讨论】:

  • 对于不需要更新 ui 的任务,添加一个在单独线程上运行的 Handler 示例会很有帮助。
猜你喜欢
  • 1970-01-01
  • 2013-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多