使用TimerTask的Blackberry IllegalStateException错误

时间:2010-10-20 17:58:54

标签: java blackberry

我有一个实现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]

2 个答案:

答案 0 :(得分:6)

基于原始问题的诊断:

您的第一步应该是阅读Timer和TimerTask的文档,该文档为IllegalStateException schedule(...)提供以下条件:

  

如果计时器的任务执行线程   例如,意外终止   因为它的stop方法被调用,   任何进一步安排任务的尝试   在计时器上会产生一个   IllegalStateException,好像是   计时器的取消方法已经   调用

你有.stop()吗?你有没有打电话给cancel()?你能检查一下这个任务是否引发了一个突然终止Timer线程的异常吗?您是否对其他Timer使用相同的TimerTask?你相信他们吗?

尝试使用广泛的异常处理程序包装TimerTask逻辑并让它直接报告以查看是否存在内部意外异常,这将导致下一次调用schedule失败,如上所述。

另外,一个挑剔,但重要的一个:当问一个包含“为什么我得到这个例外?”的问题时的最佳做法。是包括完整的异常和堆栈跟踪输出。您将获得更高质量的答案,您不必再次阅读此文本,然后必须重新编辑您的问题等。

指导您的具体错误:

好吧,阅读异常声明。看起来你已经打乱了UI引擎。所以你有两个问题:

  1. 你把计时器线程交给一个未被捕获的异常爆炸的任务,这让你感到不安。将这些内容包装在try/catch块中的好策略,其中catch操作至少以打印或记录可用的堆栈跟踪并重新抛出异常。

  2. 你打乱了UI事件逻辑,见下文......

  3. 我不知道黑莓用户界面,但可能你想要做的事情需要在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);