PopUpScreen Blocking events in Blackberry - blackberry

I am using a popup screen to show the update status of background uploading processes. I want to cancel the uploading in between. I am trying to achieve this either by addin a button to the pop up screen or with the physical backbutton of the device. But it seems that none of the events generated are caught by the app.
Here is how I am creating a popup screen and displaying it t user
DialogFieldManager manager = new DialogFieldManager();
//DialogFieldManager manager = (DialogFieldManager)getDelegate();
statusUpdate = new LabelField("Please Wait...");
manager.addCustomField(statusUpdate);
_gaugeField = new GaugeField("", 0, 100, 0, GaugeField.PERCENT);
manager.addCustomField(_gaugeField);
cncl_Btn = new ButtonField("Cancel",ButtonField.CONSUME_CLICK | ButtonField.FIELD_HCENTER | ButtonField.NEVER_DIRTY);
manager.addCustomField(cncl_Btn);
cancelFlag = 0;
cncl_Btn.setChangeListener(new FieldChangeListener()
{
public void fieldChanged(Field field, int context) {
// Auto-generated method stub
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
cancelFlag = 1;
//onClose();//as this method exited from application
// close();//this method gave me IllegalStateException
}
});
}
});
//BackUpScreen.this.addMenuItem(_viewItem);
popup = new PopupScreen(manager);
UiApplication.getUiApplication().pushScreen(popup);
Soon afther this line I am calling the actual upload process in a thread like this
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
//.... do other stuff I wanted done...
backUpThread = Thread.currentThread();
uploadItems();
}
});
But if I press the cancel button inside the popup screen its not responding. I checked this by adding a breakpoint inside the fieldchange listener method of button.
How can I do this in blackberry?

The call to invokeLater (int the second bit of code) causes that Runnable to be executed on the event thread. If anything you do on the event thread blocks then the UI will become unresponsive as you describe. Any calls that may block must not be run on the event thread.

Related

Refresh Screen to Update ListField with new Data

I am using a ListField Control to display data returned from xml webservice. I want to refresh the ListField or the screen every minute to update the ListField with new records or data.
I tried using the code below but it is not working properly (It is hanging).
public MyApp() {
// Push a screen onto the UI stack for rendering.
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().pushScreen(new MyScreen());
}
},5000,true);
}
ResponseHandler handler = new ResponseHandler();
ListField listUsers = new ListField(handler.getItem().size());
public MyScreen() {
setTitle("yQAforum");
//Fetch the xml from the web service
String wsReturnString = GlobalV.Fetch_Webservice("myDs");
//Parse returned xml
SAXParserImpl saxparser = new SAXParserImpl();
ByteArrayInputStream stream = new ByteArrayInputStream(wsReturnString.getBytes());
try {
saxparser.parse( stream, handler );
}
catch ( Exception e ) {
response.setText( "Unable to parse response.");
}
//Return vector sze from the handler class
listUsers.setSize(handler.getItem().size());
listUsers.setCallback(this);
listUsers.setEmptyString("No Users found", 0);
add(listUsers);
}
You are attempting to fetch data from your webservice on the UI thread. That's almost always the wrong thing to do.
The UI thread (also known as the main thread) is responsible for drawing the UI, and tracking user actions, like touches, or navigation via a trackpad/trackball. If the UI thread is blocked waiting for a remote web server to respond, it cannot service the UI.
There's a couple changes you should make:
public MyApp() {
// Push a screen onto the UI stack for rendering.
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().pushScreen(new MyScreen());
}
},5000,true);
}
should be changed to
public MyApp() {
// Push a screen onto the UI stack for rendering.
pushScreen(new MyScreen());
}
The MyApp() constructor will already be called on the UI thread, so there is no need to use invokeLater() to perform the pushScreen() call on the UI thread. It already will be called on the UI thread, if run from within the MyApp constructor. Also, the 5000 msec delay isn't really helpful. This will just delay the startup of your app by 5 seconds, which users will hate.
If you are trying to implement a splash screen, or something similar, when the app starts up, please search stack overflow for "BlackBerry splash screen", and I'm sure you'll find results.
Now, once your MyScreen class is created, you should take care not to fetch web service results from the UI thread. The MyScreen constructor will be run on the UI thread. If you want, you can initiate a web service request on a background thread, once the screen is shown. One way to do that is to use onUiEngineAttached():
protected void onUiEngineAttached(boolean attached) {
if (attached) {
// TODO: you might want to show some sort of animated
// progress UI here, so the user knows you are fetching data
Timer timer = new Timer();
// schedule the web service task to run every minute
timer.schedule(new WebServiceTask(), 0, 60*1000);
}
}
public MyScreen() {
setTitle("yQAforum");
listUsers.setEmptyString("No Users found", 0);
listUsers.setCallback(this);
add(listUsers);
}
private class WebServiceTask extends TimerTask {
public void run() {
//Fetch the xml from the web service
String wsReturnString = GlobalV.Fetch_Webservice("myDs");
//Parse returned xml
SAXParserImpl saxparser = new SAXParserImpl();
ByteArrayInputStream stream = new ByteArrayInputStream(wsReturnString.getBytes());
try {
saxparser.parse( stream, handler );
}
catch ( Exception e ) {
response.setText( "Unable to parse response.");
}
// now, update the UI back on the UI thread:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
// TODO: record the currently selected, or focused, row
//Return vector sze from the handler class
listUsers.setSize(handler.getItem().size());
// Note: if you don't see the list content update, you might need to call
// listUsers.invalidate();
// here to force a refresh. I can't remember if calling setSize() is enough.
// TODO: set the previously selected, or focused, row
}
});
}
}
You'll need to add some error handling, in case the web service doesn't respond, or takes longer than a minute (you wouldn't want to be making a new request, if the last one hadn't finished).
But, this should get you started.
Note: once you fix the problem with running network code on the UI thread, you may still find that your code doesn't work. There could be problems fetching the web service data. You'll have to debug that. I am only showing you one problem with the code posted. If you still have problems with the web service fetch, post another question (with the UI thread problem fixed). Thanks.

BlackBerry Please Wait Screen with Time out

Hello I am trying to create a please wait screen.This screen will appear when my program requests data from web service and will hide when the process is finished.Also I want to add a time out if request process lasts longer than 90 seconds.
can anyone help or show me a guiding example about that matter.
public static void showBusyDialog() {
try
{
if (busyDialog == null) {
busyDialog = new Dialog("Please Wait", null, null, 0, Bitmap.getPredefinedBitmap(Bitmap.HOURGLASS));
busyDialog.setEscapeEnabled(false);
}
synchronized (Application.getEventLock()) {
busyDialog.show();
}
}
catch(Exception e)
{
}
}
and my hiding code is
public static void hideBusyDialog() {
try
{
if (busyDialog == null) {
// busyDialog = new Dialog("Please wait...", null, null, 0, Bitmap.getPredefinedBitmap(Bitmap.HOURGLASS));
busyDialog.setEscapeEnabled(false);
}
synchronized (Application.getEventLock()) {
busyDialog.close();
}
}catch(Exception e)
{
}
}
Many BlackBerry® smartphone applications need to wait for some network activity (or another blocking operation, which must process in the background), while still holding up the User Interface (UI) and displaying a progress indicator.
You can follow through this links
Links
Sample "Please Wait" screen - part 1
Sample "Please Wait" screen - part 2
Sample "Please Wait" screen - part 4
you can download simple examples for Please wait screen
PleaseWait1.zip 25 KB
PleaseWait2.zip 25 KB
PleaseWait3.zip 25 KB
Note :in case above Links not working then just follow following contents
There seem to be two common issues when programming this:
1) As applications are not allowed to block the Event Thread, how do they get the UI processing to wait?
2)How can the background Thread update the UI?
This article is intended to help with these issues and provide a fully functioning "Please Wait" sample Popup Screen. However, as there is quite a lot to explain, in this first article, we will just create a popup screen that will show itself, hold up the UI, and then remove itself once the background processing has finished. This does not give us any progress indication, nor does it let the user cancel the wait. These points will be covered in a followup article. But the code supplied with this article will be useful anyway, especially when the duration of the background processing is not known and the user may not cancel the processing.
First, we start with the background processing we need to run. While this could be anything, typically this will be network processing, like the following:
httpConn = (HttpConnection)Connector.open(_url + ";deviceside=true");
responseCode = httpConn.getResponseCode();
responseMessage = "Response Code: " + Integer.toString(responseCode);
To initiate this network processing, we have a MainScreen that contains
1) A BasicEditField that allows the entry of a URL
2) A RichTextField that should display the response code (or error message). Here are the important parts of that screen:
BasicEditField _requestedURLField = new BasicEditField("http://", "www.blackberry.com", 255, BasicEditField.FILTER_URL);
RichTextField _responseField = new RichTextField("<response code>", RichTextField.NON_FOCUSABLE);
We would like the MainScreen to be updated with the result. As noted above, background processing can't directly update the UI; UI updating code must be on the Event Thread. There are several ways to get a background process onto the Event Thread, see the related article for more. In this case, we will use the following code:
// Make things final so we can use them in the inner class
final String textString = responseMessage;
final RichTextField rtf = _resultField;
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
rtf.setText(textString);
}
});
Now we must define the PleaseWaitPopupScreen to be displayed while waiting.
To give the user something to look at while they are waiting, we have an animated .gif, which is diplayed using the code in the AnimatedGIFField (see related link). And, so the user knows what they are waiting for, the PleaseWaitPopupScreen is supplied with a String to display, as the following constructor shows:
private PleaseWaitPopupScreen(String text) {
super(new VerticalFieldManager(VerticalFieldManager.VERTICAL_SCROLL | VerticalFieldManager.VERTICAL_SCROLLBAR));
GIFEncodedImage ourAnimation = (GIFEncodedImage) GIFEncodedImage.getEncodedImageResource("cycle.agif");
_ourAnimation = new AnimatedGIFField(ourAnimation, Field.FIELD_HCENTER);
this.add(_ourAnimation);
_ourLabelField = new LabelField(text, Field.FIELD_HCENTER);
this.add(_ourLabelField);
}
PleaseWaitPopupScreen provides a method – showScreenAndWait(..) – which will create and display the Popup screen, run the Background processing, and then dismiss the Popup screen.
The final piece of the puzzle involves supplying showScreenAndWait(..) with the processing to run.
Java has the concept of a Runnable, which is an Object that contains a public void run() method that should be executed. In this case, we have the Connection code and screen update code, given above, that should be executed. So, this code is packaged up into a new Runnable Object, which is supplied to showScreenAndWait(..). And here is that method. Note how a new Thread is created and run.
public static void showScreenAndWait(final Runnable runThis, String text) {
final PleaseWaitPopupScreen thisScreen = new PleaseWaitPopupScreen(text);
Thread threadToRun = new Thread() {
public void run() {
// First, display this screen
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().pushScreen(thisScreen);
}
});
// Now run the code that must be executed in the Background
try {
runThis.run();
} catch (Throwable t) {
t.printStackTrace();
throw new RuntimeException("Exception detected while waiting: " + t.toString());
}
// Now dismiss this screen
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().popScreen(thisScreen);
}
});
}
};
threadToRun.start();
}
And this is the key part of the PleaseWaitPopupScreen. Note how this code will create and display a Popup screen to the user, including an animated icon, while it is running the background processing. Input from the user is blocked by the Popup screen until the processing completes. The originating screen is updated as a result of the background processing.
Download the associated .zip archive, which contains the source included in this article.
In the next article, we will extend this code to be able to handle:
a) Status updates from the Background Thread
b) "Time to go" indication
c) Being cancelled by the BlackBerry smartphone user
Just put timer after you show busy dialog.
showBusyDialog();
Timer timer = new Timer();
TimerTask task = new TimerTask() {
public void run() {
hideBusyDialog();
}
};
timer.schedule(task, 9000);
this is for time out. If the process finishes less than 90 seconds you should call
timer.cancel();
timer = null;
task = null;

How can I use A dialog with No BUTTON and automatically Closes? On BlackBerry

I need to use a dialog. That appears 2-3 seconds and after closes automatically.
Which object should I use On BlackBerry?
you can also use
Status.show(String message)
Shows a status screen for two seconds.
or
Status.show(String message, Bitmap bitmap, int time)
Shows a status screen with specified
icon, for specified time.
Create a class that extends PopupScreen and use a TimerTask to automatically close it. So you would have code in your constructor that looks sort of like this:
Timer timer = new Timer();
timer.schedule(new TimerTask(){
public void run()
{
if(TestScreen.this.isDisplayed())
{
synchronized (Application.getEventLock())
{
TestScreen.this.close();
}
}
}
}, WAIT_TIME_IN_MILLISECONDS);

Trouble bringing a Blackberry App to Foreground

I have an app that is listening in background and when the user clicks "send" it displays a dialogue. However I need to bring my app to foreground so the user answers some questions before letting the message go. but I haven't been able to do this, this is the code in my SendListener:
SendListener sl = new SendListener(){
public boolean sendMessage(Message msg){
Dialog myDialog = new Dialog(Dialog.D_OK,
"message from within SendListener",
Dialog.OK,Bitmap.getPredefinedBitmap(Bitmap.EXCLAMATION),
Dialog.GLOBAL_STATUS)
{
//Override inHolster to prevent the Dialog from being dismissed
//when a user holsters their BlackBerry. This can
//cause a deadlock situation as the Messages
//application tries to save a draft of the message
//while the SendListener is waiting for the user to
//dismiss the Dialog.
public void inHolster()
{
}
};
//Obtain the application triggering the SendListener.
Application currentApp = Application.getApplication();
//Detect if the application is a UiApplication (has a GUI).
if( currentApp instanceof UiApplication )
{
//The sendMessage method is being triggered from
//within a UiApplication.
//Display the dialog using is show method.
myDialog.show();
App.requestForeground();
}
else
{
//The sendMessage method is being triggered from
// within an application (background application).
Ui.getUiEngine().pushGlobalScreen( myDialog, 1,
UiEngine.GLOBAL_MODAL );
}
return true;
}
};
store.addSendListener(sl);
App is an object I created above:
Application App = Application.getApplication();
I have also tried to invoke the App to foreground using its processID but so far no luck.
i have managed to achieve something similar to what you're describing but the difference is, my dialogs are displayed asynchronously, which might actually be easier... so in your case..
the first i could suggest you try is get the event lock before pushing the screen, ala:
synchronized(Application.getEventLock()){
final UiEngine ui = Ui.getUiEngine();
ui.pushGlobalScreen(theScreen, 1, UiEngine.GLOBAL_MODAL);
}
I would also just create a custom class of type MainScreen and push that instead of plain Dialog.
There, that's better (now with code formatting).
public class MYSendListener implements SendListener {
private UiApplication _myApp;
public MySendListener(UiApplication myApp) {
_myApp = myApp;
}
public boolean sendMessage(Message m) {
...
_myApp.requestForeground();
}
}
Cache your app instance inside your send listener when you construct it, and use that when sendMessage is fired.
Application.getApplication() only gets you the app of the calling thread.

Navigate one screen to another screen based on time period in BlackBerry app

For my Blackberry application I am using a start up screen with progress bar. I am filling the progress bar using a timer and after the progress bar is complete, I need to navigate to another screen.
I am checking like this, where 'i' is time, increasing from 0 to 100.
timer.cancel();
if(i>=99)
UiApplication.getUiApplication().pushScreen(new TipCalculatorScreen());
This code is not working.
For progress bar I am using code like this:
private GaugeField percentGauge;
percentGauge = new GaugeField(null, 0, 100,50, GaugeField.PERCENT);
timer=new Timer();
timer.scheduleAtFixedRate(new TimerTask(){
int i=0;
public void run() {
percentGauge.setValue(i);
i++;
if(i>=99)
{
timer.cancel();
//for page navigating i am given like this here screen is not navigating getting error
UiApplication.getUiApplication().pushScreen(new nextscreen());
}
}
}, 100,100);
You need to make changes to the UI on the UI thread. The TimerTask is executing on its own thread. Instead of
UiApplication.getUiApplication().pushScreen(new nextscreen());
you should use
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication()..pushScreen(new nextscreen());
}
});
The update to your gauge control probably needs the same treatment.

Resources