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