【问题标题】:When are runnables posted in postDelayed actually executed on Android?postDelayed 中发布的可运行文件何时在 Android 上实际执行?
【发布时间】:2016-11-15 23:11:24
【问题描述】:

有一段代码我使用 postDelayed 和一些在主线程上执行的其他代码。我运行了几次,总是看到以下输出:

07-13 14:22:18.511 15376-15376/sample1.com.sample_1 D/MainActivity: i = 0

....

07-13 14:22:18.601 15376-15376/sample1.com.sample_1 D/MainActivity: onResume 07-13 14:22:18.601 15376-15376/sample1.com.sample_1 D/MainActivity: postDelayed

正如我从日志输出中看到的,我的延迟是 50 毫秒并不重要。大约 100 毫秒 (601 - 511 = 90) 后输入消息“postDelayed”。看起来延迟的可运行对象已添加到我的 UI 线程的消息队列的末尾。但无论如何,是否有任何关于何时输入 postDelayed 的保证?可以在for循环中间输入吗?

package sample1.com.sample_1;

import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.d("MainActivity", "postDelayed");
            }
        }, 10);
        for (int i = 0; i < 10000; i++) {
            Log.d("MainActivity", "i = " + i);
        }
    }

    @Override
    protected void onResume() {
        Log.d("MainActivity", "onResume");
        super.onResume();

    }
}

【问题讨论】:

  • Android 限制主线程中的UI操作是为了防止你想做的事情。
  • @Harlon,我不确定我是否理解你。

标签: android android-handler postdelayed


【解决方案1】:

使用post()实际上调用sendMessageDelayed(getPostMessage(r), 0),而postDelayed()将调用sendMessageDelayed(getPostMessage(r), delayMillis),它们是相似的。

post...() 方法最终将调用queue.enqueueMessage,与when 参数不同,它决定将 msg 插入消息队列的位置。您可以更改队列中的味精,但不能中断已运行的味精。

【讨论】:

    【解决方案2】:

    还有来自其他服务和应用程序的日志,因此根据日志输出计算 Handler 延迟是不正确的。 Android 上的日志机制有自己的队列,因此您的消息实际上可能会由于队列中的其他日志而延迟。

    我的建议是使用System.nanoTime() 来计算处理程序延迟之间的时间。据我所知,它给出了最精确的计时器值。

    最后回答您的问题,不,您无法确定某项行动发生的确切时间。有成千上万(如果不是数百万)不同的条件可能会延迟您的应用程序的操作,尤其是在它是异步操作的情况下。

    编辑:该延迟不能保证 50 毫秒的延迟,但可以保证“至少”50 毫秒的延迟。

    【讨论】:

    • 是的,看起来postDelayed(r, 10) 保证至少 10 毫秒。这是 nanoTime gist.github.com/anonymous/70f301a06959f91b96302d6a6adddd6d 的示例
    • 07-13 17:58:36.391 30902-30902/sample1.com.sample_1 D/MainActivity: timeHandler = 22583545657183 07-13 17:58:36.281 30902-30902/sample1.com.sample_1 D /MainActivity: beforeTimeHandler = 22583437099224 差异是 108557959 纳秒 = 10 毫秒(大约)
    【解决方案3】:

    在跟踪Handler.postDelay() 的代码之后,看起来最终MessageQueue.enqueueMessage() 被调用了。从代码来看,它似乎在消息队列中无限循环,直到它到达末尾或直到当前任务时间高于我们的延迟时间,然后将任务插入到队列中的那个位置。这意味着你的任务执行之前的队列需要很长时间,你应该在你想要的几毫秒内执行你的任务。

    我猜你的操作不是问题,而是 Android 正忙于渲染你的 UI 和其他内部工作的主线程,这会延迟你的任务。据推测,在您的活动上执行onCreateonStartonResume 中的所有代码,并且它扩展的类在您的 postDelay 时间 + 10 毫秒之前排队。

    100ms 大约是 6 帧,因此它可能只是显示 Activity 的 UI 所花费的时间,请尝试在单击按钮时执行 postDelay,我相信时间会更容易预测,因为 UI 和 Activity 不是正在安装或拆除。

    【讨论】:

    • 07-13 17:49:45.781 14332-14332/sample1.com.sample_1 D/MainActivity: i = 0 ..... 07-13 17:49:45.871 14332-14332/sample1 .com.sample_1 D/MainActivity: postDelayed 看起来将代码移动到按钮单击没有任何区别
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-04
    • 2014-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-21
    相关资源
    最近更新 更多