2010-03-26 34 views
3

我试图让我的黑莓应用程序显示一个自定义的模式对话框,并让开启线程等待,直到用户关闭对话框屏幕。在事件线程上抛出的“由非事件线程调用的pushModalScreen”

final Screen dialog = new FullScreen(); 

...// Fields are added to dialog 

Application.getApplication().invokeAndWait(new Runnable() 
{ 

    public void run() 
    { 
     Application.getUiApplication().pushModalScreen(dialog);    
    } 
}); 

这是抛出一个异常,它说“pushModalScreen由非事件线程被称为”尽管我使用invokeAndWait从事件线程中调用pushModalScreen。

关于真正问题是什么的任何想法?

这里是复制此问题的代码:

package com.test; 

import net.rim.device.api.ui.*; 
import net.rim.device.api.ui.component.*; 
import net.rim.device.api.ui.container.*; 

public class Application extends UiApplication { 
    public static void main(String[] args) 
    { 
     new Application(); 
    } 

    private Application() 
    { 
     new Thread() 
     { 
      public void run() 
      { 
       Application.this.enterEventDispatcher(); 
      } 
     }.start(); 

     final Screen dialog = new FullScreen(); 
     final ButtonField closeButton = new ButtonField("Close Dialog"); 
     closeButton.setChangeListener(new FieldChangeListener() 
     { 

      public void fieldChanged(Field field, int context) 
      { 
       Application.getUiApplication().popScreen(dialog); 
      } 
     }); 
     dialog.add(closeButton); 
     Application.getApplication().invokeAndWait(new Runnable() 
     { 

      public void run() 
      { 
       try 
       { 
        Application.getUiApplication().pushModalScreen(dialog); 
       } 
       catch (Exception e) 
       { 
        // To see the Exception in the debugger 
        throw new RuntimeException(e.getMessage()); 
       } 
      } 
     }); 

     System.exit(0); 
    } 
} 

我使用的组件包版本4.5.0。

+0

这是一个UIApplication的或后台应用程序? – 2010-03-26 17:29:13

+0

您是否在某些系统监听器(例如PhoneListener或SendListener)中使用此应用程序? – 2010-03-26 17:39:14

+0

这是一个UI应用程序。我已经添加了演示项目的代码,以说明问题。 – JGWeissman 2010-03-26 18:04:31

回答

2

大厦最大Gontar的观察,使用了invokeLater来代替invokeAndWait时没有抛出异常,完整解决方案是实现invokeAndWait正确出来的invokeLater和Java的同步方法:

public static void invokeAndWait(final Application application, 
    final Runnable runnable) 
{ 
    final Object syncEvent = new Object(); 
    synchronized(syncEvent) 
    { 
     application.invokeLater(new Runnable() 
     { 

      public void run() 
      { 
       runnable.run(); 
       synchronized(syncEvent) 
       { 
        syncEvent.notify(); 
       } 
      } 
     }); 
     try 
     { 
      syncEvent.wait(); 
     } 
     catch (InterruptedException e) 
     { 
      // This should not happen 
      throw new RuntimeException(e.getMessage()); 
     } 
    } 
} 

不幸的是,invokeAndWait方法不能被重写,所以必须小心地调用这个静态版本。

+1

我无法想象这种过于复杂的代码永远是一个很好的解决方案的情况。 – Nate 2013-06-18 02:36:51

2

好像有一堆代码在那里是不必要的。

public class Application extends UiApplication { 
    public static void main(String[] args) 
    { 
     new Application().enterEventDispatcher(); 
    } 

private Application() 
{ 
    final Screen dialog = new FullScreen(); 
    final ButtonField closeButton = new ButtonField("Close Dialog"); 
    closeButton.setChangeListener(new FieldChangeListener() 
    { 
     public void fieldChanged(Field field, int context) 
     { 
      Application.getUiApplication().popScreen(dialog); 
     } 
    }); 
    dialog.add(closeButton); 

    // this call will block the current event thread 
    pushModalScreen(dialog); 

    System.exit(0); 
    } 
} 
+0

如何在'Application'构造函数(在'enterEventDispatcher()'之前运行)调用'System.exit(0)'应该是正确的? – Nate 2013-10-21 08:14:38

0

使用此:

UiApplication.getUiApplication().invokeAndWait(new Runnable() { 
    public void run() { 
     pushScreen(new MyScreen()); 
    } 
});