【问题标题】:Android Timer: postDelayed vs. scheduleAndroid 计时器:postDelayed 与 schedule
【发布时间】:2014-11-06 02:57:18
【问题描述】:

我需要每 200 毫秒完成一次工作,并且我需要它平滑且均匀。要做的任务是中等权重(在这两种情况下,问题 1 和 2)。 从社区中搜索计时器看起来最好的解决方案是使用处理程序、runnable 和 postDelayed(),(How to set timer in android?)。

更新问题:

-如果我必须与 UI 交互,postDelayed()schedule()/scheduleAtFixedRate(),哪种方式最精确、最快速?

-如果我不必与 UI 交互,postDelayed()schedule()/scheduleAtFixedRate(),哪种方式最精确和快速?

-两种方式都可以在主进程上执行还是在单独的进程上执行?怎么样?

这样我就有了主类本地对象,但它是一个新线程吗?这是一个好习惯吗?

timer.schedule( new TimerTask() {           
        @Override
        public void run() {
                    textview.setText(str);
                    //other stuff            
                                     }
            }, 0, 200);

接下来是另外一个有schedule的,任务是在一个单独的任务中,不是定时器本身,我猜,而且我不能直接和UI交互,我猜...

timer.schedule( new aclass(), 0, 200);

处理方式(来自 Dave.B):

Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() {
    @Override
    public void run() {
        TextView.setText(str);
        // other stuff
        timerHandler.postDelayed(this, 500); }
};

@Override
public void onCreate(Bundle savedInstanceState) {
...
timerHandler.postDelayed(timerRunnable, 0);
}

【问题讨论】:

  • 如果你想在主线程上完成工作,使用带有postDelayed()的处理程序。否则,您将浪费更多时间将事件发布回主线程。
  • 计时器很快,所以我想我需要一个新线程,但我必须与 UI 交互
  • 最后我认为在一个单独的“帮助器”类中使用处理程序(第三个示例)。这应该把所有事情都放在另一个线程上,对吗?
  • @Alex MDC.but 我必须制作另一个类似的应用程序,它也与 UI 交互。你说如果我在单独的类上运行它可能会更慢?

标签: android timer


【解决方案1】:

Timer 在单独的线程上执行其任务,该线程仅用于服务由该特定计时器创建的任务。 Handler 在其 Looper 的线程上运行其任务,该线程可能是也可能不是 UI 线程。一般来说,如果您在单独的线程上使用Handler,这两个类之间没有太大区别。但在 Android 中使用HandlerHandlerThread 更为常见。

如果需要与 UI 交互,最好在主线程上使用Handler,以避免上下文切换。但在这种情况下,可能会有一些延迟,因为此类计时器的性能将取决于 UI 的整体性能。

UPDATE:在第三个示例中,Runnable 在主线程上执行。我假设此示例中的所有代码都位于 Activity 子类中。

HandlerTimerScheduledExecutorService 使用类似的方法来调度任务。我不确定从一种实现切换到另一种实现时,您能否在精度或性能上获得显着变化。

更新:最后,我向您推荐以下选择计时器的方法:

  1. 如果您需要在单独的线程上运行任务或/并且该任务对于主线程来说过于繁重,请使用 ScheduledExecutorService
  2. 使用Handler 在主线程上运行任务或者如果您需要它的消息队列功能。
  3. 不要使用Timer,而是使用ScheduledExecutorService

【讨论】:

  • 问题 1:我认为任务和计时器都应该在单独的线程上(或者我应该说在单独的进程上?目的是不冻结 UI,就像任何繁重的工作一样) ,还考虑到我需要的计时器很快。
  • 问题2:在我添加的第三个示例中,任务是在单独的线程/进程上调用任务吗?
  • @Jackd, Handler 可以用给定的Looper 创建,Looper 表示消息循环。每个 Android 应用程序都有一个绑定到主线程的主 Looper,可以通过 Looper.getMainLooper()Context.getMainLooper() 访问。因此,您可以使用Handler 在主线程上运行定期任务。是否应该在主线程上运行它取决于您的问题。我认为在大多数情况下,您应该在主线程上运行 UI 绑定的周期性任务,因为此类任务不是非常精确的计时器。
  • 在一个单独的进程中运行如此轻量级的周期性任务没有任何意义,所以HandlerTimerExecutors 都是inproc。如果你真的需要它,你可以在一个单独的进程中运行这样的任务,但在这种情况下你必须明白你为什么要这样做。
  • @Jackd,在第三个示例中,Runnable 在主线程上执行。我假设此示例中的所有代码都位于 Activity 子类中。
【解决方案2】:

我宁愿使用ScheduledThreadPoolExecutor,因为计时器按顺序运行它的任务,所以如果一次有多个任务,剩余的任务将被延迟。虽然 ScheduledThreadPoolExecutor 有线程池并且它允许多个任务并行运行,所以不会有延迟。

Handler postdelayed 方法用于将您的可运行文件发布到 Android 中的主 UI 线程,您需要它来执行所有与 UI 相关的工作。不要把 timer 和 Handler postdelayed 混淆了

编辑 1: 对于 UI 相关的东西,您可以使用处理程序 postdelayed。例如

handler.postDelayed(new Runnable() {
        public void run() {
          textview.setText(str);
          //other UI related stuff      
        }
    }, 200);

【讨论】:

  • 我认为你错了,可以为任何线程(甚至不是ui线程)创建处理程序实例,有像runOnUiThread这样的方法,它实际上只适用于ui
猜你喜欢
  • 2020-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多