我有一个实现MainScreen的启动画面,我正在尝试使用Timer等待3秒钟来推动新屏幕。
TimerTask splashTask = new TimerTask() {
public void run() {
UiApplication.getUiApplication().pushScreen(new HomeNavigationScreen());
}
};
timer.schedule(splashTask, 3000);
然而,它抛出了IllegalStateException错误,我不确定我做错了什么?
我是eclipse和java的新手,我不知道如何查看堆栈跟踪。
这是我发现的:
ApplicationManagerImpl.processExited : process process switching to background: pid=260 java.lang.IllegalStateException: UI engine accessed without holding the event lock. Timer died: Thread[Thread-310688768,5]
答案 0 :(得分:6)
您的第一步应该是阅读Timer和TimerTask的文档,该文档为IllegalStateException
schedule(...)
提供以下条件:
如果计时器的任务执行线程 例如,意外终止 因为它的stop方法被调用, 任何进一步安排任务的尝试 在计时器上会产生一个 IllegalStateException,好像是 计时器的取消方法已经 调用
你有.stop()
吗?你有没有打电话给cancel()
?你能检查一下这个任务是否引发了一个突然终止Timer
线程的异常吗?您是否对其他Timer
使用相同的TimerTask
?你相信他们吗?
尝试使用广泛的异常处理程序包装TimerTask
逻辑并让它直接报告以查看是否存在内部意外异常,这将导致下一次调用schedule
失败,如上所述。
另外,一个挑剔,但重要的一个:当问一个包含“为什么我得到这个例外?”的问题时的最佳做法。是包括完整的异常和堆栈跟踪输出。您将获得更高质量的答案,您不必再次阅读此文本,然后必须重新编辑您的问题等。
好吧,阅读异常声明。看起来你已经打乱了UI引擎。所以你有两个问题:
你把计时器线程交给一个未被捕获的异常爆炸的任务,这让你感到不安。将这些内容包装在try/catch
块中的好策略,其中catch
操作至少以打印或记录可用的堆栈跟踪并重新抛出异常。
你打乱了UI事件逻辑,见下文......
我不知道黑莓用户界面,但可能你想要做的事情需要在GUI事件循环中完成。这KB entry应该会有所帮助。更好的是,请阅读API documentation。您需要保持GUI锁定,就像在Swing中一样,可以调用pushScreen()
。一种方法是将代码更改为通过invokeLater()
或invokeAndWait()
进行调用。
这是未经测试的,因为我从未也不打算进行任何BlackBerry开发,但它在我的脑海中反对已发布的BlackBerry API,FWIW。尝试以下其中一种:
TimerTask splashTask = new TimerTask()
{
public void run() {
final UiApplication uia = UiApplication.getUiApplication();
final Object eventLock = uia.getEventLock();
synchronized(eventLock) {
uia.pushScreen(new HomeNavigationScreen());
}
}
};
timer.schedule(splashTask, 3000);
或者,不太可能引入同步问题和潜在的死锁:
TimerTask splashTask = new TimerTask()
{
public void run() {
final UiApplication uia = UiApplication.getUiApplication();
uia.invokeLater(new Runnable() {
public void run() {
uia.pushScreen(new HomeNavigationScreen());
});
}
}
};
timer.schedule(splashTask, 3000);
答案 1 :(得分:2)
正如Andersoj指出的那样,您正在尝试在不保留UI事件锁的情况下进行UI更改。 invokeLater是一种使代码执行并安全地进行UI更改的机制。
TimerTask splashTask = new TimerTask() {
public void run() {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().pushScreen(new HomeNavigationScreen());
}
}
}
};
timer.schedule(splashTask, 3000);