Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
666 views
in Technique[技术] by (71.8m points)

user interface - "pushModalScreen called by a non-event thread" thrown on event thread

I am trying to get my Blackberry application to display a custom modal dialog, and have the opening thread wait until the user closes the dialog screen.

final Screen dialog = new FullScreen();

...// Fields are added to dialog

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

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

This is throwing an Exception which says "pushModalScreen called by a non-event thread" despite the fact that I am using invokeAndWait to call pushModalScreen from the event thread.

Any ideas about what the real problem is?

Here is the code to duplicate this problem:

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);
    }
}

I am using Component Package version 4.5.0.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Building on Max Gontar's observation that the Exception is not thrown when using invokeLater instead of invokeAndWait, the full solution is to implement invokeAndWait correctly out of invokeLater and Java's synchronization methods:

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());
        }
    }
}

Unfortunately, the invokeAndWait method cannot be overridden, so care must be used to call this static version instead.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...