问题
I tried a lot, now I need your help. What I want to do is the following: When the Blackberry app starts a yes/no dialog pops up. If user chooses "yes", do something and AFTER that continue with the startup. If user chooses "no" exit the app.
I wrote an SSCCE which should vibrate if you choose "yes" and AFTER THAT you should hear a sound. Of course I know, that the code continues after the Alert.vibrate() is called and it doesn't wait for the vibraste to finish. Anyway, it is just an example. The call to vibrate() should come first and the dialogClosed() should be processed completely before the sound is played.
The SSCCE is what I got so far. I tried lots of other things. I'm sure it can't be that difficult. I just don't get it.
Here it is:
package TestDialog;
import net.rim.device.api.system.Alert;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.DialogClosedListener;
public class TestDialog extends UiApplication
{
public static short[] SOUND_ALERT = { 523, 200, //C for 200ms
0, 200, //Pause 200ms
554, 200, //C# 200ms
0, 200, //Pause 200ms
587, 200, //D 200ms
0, 200, //Pause 200ms
622, 200 //D# 200ms
};
/**
* @param args
*/
public static void main(final String[] args)
{
final TestDialog test = new TestDialog();
test.enterEventDispatcher();
}
public TestDialog()
{
//the dialog
final Dialog d = new Dialog(Dialog.D_YES_NO, "vibrate?", Dialog.OK, Bitmap.getPredefinedBitmap(Bitmap.QUESTION), Dialog.FIELD_TOP);
d.setDialogClosedListener(new DialogClosedListener()
{
public void dialogClosed(final Dialog dialog, final int choice)
{
if (d.getSelectedValue() == Dialog.YES)
{
Alert.startVibrate(2000);
//do something which takes some time
}
else
{
System.exit(0);
}
}
});
//show the dialog
showDialog(d);
//now wait for the dialog to call notify
try
{
synchronized (this)
{
this.wait();
}
}
catch (final Exception e)
{
System.out.println(e.getMessage());
}
//finally AFTER the dialog has been closed and everything in dialogClosed() has been done, play a sound
Alert.startAudio(SOUND_ALERT, 100);
}
private void showDialog(final Dialog d)
{
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
d.doModal();
this.notify();
}
});
}
}
OK, some other SSCCE. This starts and shows a dialog, but then throws an IllegalMonitorExcpetion:
package TestDialog;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.Dialog;
public class TestDialog extends UiApplication
{
public static short[] SOUND_ALERT = { 523, 200, //C for 200ms
0, 200, //Pause 200ms
554, 200, //C# 200ms
0, 200, //Pause 200ms
587, 200, //D 200ms
0, 200, //Pause 200ms
622, 200 //D# 200ms
};
/**
* @param args
*/
public static void main(final String[] args)
{
final TestDialog test = new TestDialog();
test.enterEventDispatcher();
}
public TestDialog()
{
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
//the dialog
final Dialog d = new Dialog(Dialog.D_YES_NO, "vibrate?", Dialog.OK, Bitmap.getPredefinedBitmap(Bitmap.QUESTION), Dialog.FIELD_TOP);
if (d.doModal() == Dialog.YES)
{
System.out.println("selection made yes");
this.notify();
}
else
{
System.out.println("selection made no");
System.exit(0);
}
}
});
try
{
this.wait();
}
catch (final Exception e)
{
e.printStackTrace();
}
//finally AFTER the dialog has been closed and everything in dialogClosed() has been done, play a sound
System.out.println("done");
}
}
So I put a synchronized block around the wait() call, since I read, that the object must be synchronized when calling wait(). But now the app shows nothing. It runs the main-method but somewhere stops. In Simulator very strange things happen: When the simulator is still in startup and "debugger attaching" is written on the display, the main-method of the app is called. Well, here is the SSCCE with the synchronized block. Still doesn't work.
package TestDialog;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.Dialog;
public class TestDialog extends UiApplication
{
public static short[] SOUND_ALERT = { 523, 200, //C for 200ms
0, 200, //Pause 200ms
554, 200, //C# 200ms
0, 200, //Pause 200ms
587, 200, //D 200ms
0, 200, //Pause 200ms
622, 200 //D# 200ms
};
/**
* @param args
*/
public static void main(final String[] args)
{
final TestDialog test = new TestDialog();
test.enterEventDispatcher();
}
public TestDialog()
{
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
//the dialog
final Dialog d = new Dialog(Dialog.D_YES_NO, "vibrate?", Dialog.OK, Bitmap.getPredefinedBitmap(Bitmap.QUESTION), Dialog.FIELD_TOP);
if (d.doModal() == Dialog.YES)
{
System.out.println("selection made yes");
this.notify();
}
else
{
System.out.println("selection made no");
System.exit(0);
}
}
});
synchronized (this)
{
try
{
this.wait();
}
catch (final Exception e)
{
e.printStackTrace();
}
}
//finally AFTER the dialog has been closed and everything in dialogClosed() has been done, play a sound
System.out.println("done");
}
}
And finally I tried making use of busy waiting. Still no success. The Dialog just doesn't pop up. Even with the Thread.sleep(1000) in the while loop in the main thread the UI thread seems not to work. Here is the SSCCE with the busy waiting:
package TestDialog;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.Dialog;
public class TestDialog extends UiApplication
{
/**
* @param args
*/
public static void main(final String[] args)
{
final TestDialog test = new TestDialog();
test.enterEventDispatcher();
}
private volatile boolean _blocked = true;
public TestDialog()
{
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
//the dialog
final Dialog d = new Dialog(Dialog.D_YES_NO, "vibrate?", Dialog.OK, Bitmap.getPredefinedBitmap(Bitmap.QUESTION), Dialog.FIELD_TOP);
if (d.doModal() == Dialog.YES)
{
System.out.println("selection made yes");
_blocked = false;
}
else
{
System.out.println("selection made no");
System.exit(0);
}
}
});
while (_blocked)
{
try
{
Thread.sleep(1000);
}
catch (final Exception e)
{
//safety catch
}
}
finish();
}
private void finish()
{
System.out.println("done");
}
}
Thanks for your help.
Haferblues
回答1:
HI I finally got an answer in the Blackberry forum here: http://supportforums.blackberry.com/t5/Java-Development/Startup-YES-NO-Dialog-should-stop-the-launchign-process-of-the/m-p/1725085
The final solution, which works for me (and looks much nicer then everything I did above) is as follows:
package TestDialog;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.RichTextField;
import net.rim.device.api.ui.container.MainScreen;
public class TestDialog extends UiApplication implements Runnable
{
/**
* @param args
*/
public static void main(final String[] args)
{
final TestDialog test = new TestDialog();
test.invokeLater(test);
test.enterEventDispatcher();
}
public TestDialog()
{
}
public void run()
{
final int answer = Dialog.ask(Dialog.D_YES_NO, "continue?");
// pushGlobalScreen(new Dialog(Dialog.D_YES_NO, "continue?", 0, null, Dialog.GLOBAL_STATUS), 1, TestDialog.GLOBAL_QUEUE | TestDialog.GLOBAL_MODAL);
if (answer == Dialog.YES)
{
System.out.println("user clicked yes");
}
else
{
System.exit(0);
}
pushScreen(new MyScreen("App loaded"));
}
class MyScreen extends MainScreen
{
public MyScreen(final String msg)
{
final LabelField title = new LabelField("First Screen", LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);
setTitle(title);
this.add(new RichTextField(msg));
}
}
}
Thanks for the great support on both sides.
回答2:
Use invokeAndWait instead invokeLater.
private void showDialog(final Dialog d)
{
UiApplication.getUiApplication().invokeAndWait(new Runnable()
{
public void run()
{
d.doModal();
this.notify();
}
});
}
来源:https://stackoverflow.com/questions/10620605/blackberry-show-dialog-on-startup-and-wait-until-dialog-closes