为什么我的android应用程序在调用Thread.sleep时跳过帧?

时间:2012-10-22 01:54:19

标签: java android sleep

我正在编写一个Android应用程序,它需要显示几千分之一秒的文本,然后再将其删除。我现在拥有的是显示文本,然后使用Thread.sleep,然后将文本设置回null。相反,当我按下按钮时,应用程序会挂起设定的时间,文本永远不会出现,并且logcat会显示“跳过xxx帧!应用程序可能在其主线程上做了太多工作”。发生了什么,是否有更好的做事方式?

2 个答案:

答案 0 :(得分:4)

尝试使用runnable。

private Handler mHandler = new Handler();

//code to make text appear...

    mHandler.postDelayed(makeTextDisapear , 3000); // Replace 3000 with the number of milliseconds you want the text to display.

    private Runnable makeTextDisapear = new Runnable() {
            public void run() {
                // code to make text dissapear

                }
            };

答案 1 :(得分:2)

虽然其他答案有助于解决您的问题,但您的问题也是为什么会发生这种情况:

调用Thread.sleep()静态方法中的任何一个将调用该方法的Thread置于(大致)指定的时间内暂停状态(不保证与指定时间完全匹配) )。

在Android中,Ui操作必须在'main'ui线程上执行,因为Ui框架不是设计为线程安全的。也就是说,当您设置TextView的文本时,您必须在主线程上调用textView.setText(...)setText会向主Looper发布消息,以重新布局TextCon(和父级)并使其无效。在不久的将来的某个时刻,将处理这些消息并更新视图层次结构。

setText不直接执行此工作,因为此工作负载很重,直接执行此操作不会允许框架批处理此类请求。

如果你然后调用Thread.sleep(...),你将主ui线程置于暂停状态,但是,这个线程通常会执行TextView和父级的重新布局和失效。

Android希望能够在16ms以内渲染新帧(如果有任何变化)以保持大于60fps。如果你的主线程正在做一些密集的事情,或者暂停(通过休眠)任何可能会威胁16ms的重要时间,你看到的错误消息将被发布到logcat。

虽然在Lollipop中实际渲染是在自己的渲染线程上执行的,但它仍然需要从主线程中及时更新。

至于如何解决这个问题,请参阅Jason的回答,或者使用

将延迟的runnable发布到视图本身(而不是直接处理器实例)
textView.setText("show me!");    
textView.postDelayed(new Runnable() { 
     public void run() { 
         textView.setText(""); 
     }
}, 30);

如果这种情况经常发生,请每次通过将其保留为字段来避免分配Runnable

请注意,在任何一种情况下,创建匿名内部类(Runnable)都有可能使内存泄漏Activity,但这是另一回事。