【问题标题】:"pushModalScreen called by a non-event thread" thrown on event thread在事件线程上抛出“非事件线程调用的 pushModalScreen”
【发布时间】:2013-09-06 21:17:07
【问题描述】:

我正在尝试让我的 Blackberry 应用程序显示一个自定义模式对话框,并让打开线程等到用户关闭对话框屏幕。

final Screen dialog = new FullScreen();

...// Fields are added to dialog

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

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

尽管我使用 invokeAndWait 从事件线程调用 pushModalScreen,但会抛出一个异常,上面写着“非事件线程调用 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。

【问题讨论】:

  • 这是 UIApplication 还是后台应用程序?
  • 您是否在应用程序中将其与某些系统侦听器(例如 PhoneListener 或 SendListener)一起使用?
  • 这是一个 UI 应用。我已经添加了演示项目的代码来说明问题的问题。
  • 我相信 Bradley 的回答指向了问题的核心,即 enterEventDispatcher() 的调用没有按顺序在调用 invokeAndWait 之前运行,因此可能还没有可用的 UI 线程。

标签: user-interface blackberry


【解决方案1】:

基于 Max Gontar 的观察,即使用 invokeLater 而不是 invokeAndWait 时不会引发异常,完整的解决方案是在 invokeLater 和 Java 的同步方法之外正确实现 invokeAndWait:

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 方法不能被覆盖,所以必须小心调用这个静态版本。

【讨论】:

  • 我无法想象这种过于复杂的代码会成为一个好的解决方案的情况。
【解决方案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);
   }
}

【讨论】:

  • 究竟如何从Application 构造函数(在enterEventDispatcher() 之前运行)调用System.exit(0) 应该是正确的?
【解决方案3】:

使用这个:

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

【讨论】:

    猜你喜欢
    • 2011-01-27
    • 1970-01-01
    • 1970-01-01
    • 2013-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多