2010-03-26 32 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()); 
    } 
});