Monday, March 2, 2009

Code : Allow a background listener to detect and update a GUI application


When alternate entry points are used, an application may consists of both a background listening thread and a foreground graphical user interface (GUI) application. In many cases, it is desired that the background listening thread detects that the GUI portion of an application is running, and updates the screen to alert the user of an event.

The following example makes use of two entry points. The FolderListener is set to auto-start through an alternate entry point, and the GUI portion of the application is started when the user clicks on the application icon on their BlackBerry device.

Note: This example uses a FolderListener, but this principle can be applied to any background listening thread.

Create an alternate entry point for an application:

  1. Create a project in the BlackBerry Java Development Environment (JDE).
  2. Right-click the project and click Properties.
  3. Click the Application tab.
  4. In the Project type drop-down list, click Alternate CLDC Application Entry Point.
  5. In the Alternate entry point for drop-down list, select the project that you wish to auto-start.
  6. In the Arguments passed to field, type init (This can be any string, init is used in the sample below).
  7. Select the System module option.
  8. Select the Auto-run on startup option.
  9. Click OK.

/**
* FolderListenerGUI.java
*/
package com.samples.folderListener;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.system.*;
public class FolderListenerGUI extends UiApplication
{
private MainScreen mainScreen;
private static RichTextField newMailNotifier;
public static void main(String[] args)
{
boolean startup = false;
//Check parameters to see if the application was entered
//through the alternate application entry point.
for (int i=0; i<args.length; ++i)
{
if (args[i].startsWith("init"))
{
startup = true;
}
}
if (startup)
{
//Entered through the alternate application entry point.
//Enable folderlistener on startup.
FolderListenerApp.waitForSingleton();
} else
{
//Entered by selecting the application icon on the ribbon.
//Start the FolderListenerGUI.
FolderListenerGUI app = new FolderListenerGUI();
app.enterEventDispatcher();
}
}
public FolderListenerGUI()
{
//Pass a reference to the FolderListenerGUI
//to the FolderListenerApp.
FolderListenerApp.waitForSingleton().
setFolderListenerGUI(this);
//Initialize mainScreen.
mainScreen = new MainScreen();
//Initialize the fields.
newMailNotifier = new RichTextField("No mail yet...",
RichTextField.NON_FOCUSABLE);
LabelField title = new LabelField("Folder Listener GUI",
LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);
mainScreen.setTitle(title);
mainScreen.add(newMailNotifier);
//Display the main screen
pushScreen(mainScreen);
}
//Update the RichTextField with a new mail message.
public static void NewMailArrived()
{
newMailNotifier.setText("New mail arrived!");
}
//Remove the FolderListenerGUI instance from
//FolderListenerApp on exit.
protected void onExit()
{
//Remove the reference to FolderListenerGUI
//from FolderListenerApp.
FolderListenerApp.waitForSingleton().unsetFolderListenerGUI();
}
}
/**
* FolderListenerApp.java
*
*/
package com.samples.folderListener;
import net.rim.blackberry.api.mail.*;
import net.rim.blackberry.api.mail.event.*;
import net.rim.device.api.system.*;
import net.rim.blackberry.api.mail.*;
public final class FolderListenerApp implements FolderListener {
private FolderListenerGUI folderListenerGUI = null;
public static final long RTSID_MY_APP = 0x7451402f595f81a5L;
public FolderListenerApp()
{
try
{
//Get the store from the default instance.
Store store = Session.getDefaultInstance().getStore();
//Add the folder listener to the store.
store.addFolderListener(this);
}
catch (Exception e)
{
System.out.println(e.toString());
}
}
//Returns an instance of the running FolderListenerApp.
public static FolderListenerApp waitForSingleton()
{
//Ensure this is a singleton instance.
//Open the RuntimeStore.
RuntimeStore store = RuntimeStore.getRuntimeStore();
//Obtain the reference of FolderListenerApp.
Object obj = store.get(RTSID_MY_APP);
//If obj is null, there is no current reference
//to FolderListenerApp. Start a new instance
// of FolderListenerApp if one is not running.
if (obj == null)
{
//Store a reference to this instance in the RuntimeStore.
store.put(RTSID_MY_APP, new FolderListenerApp());
return (FolderListenerApp)store.get(RTSID_MY_APP);
} else
{
return (FolderListenerApp)obj;
}
}
//Called when a new message is created.
public void messagesAdded(FolderEvent e)
{
//Get the message that fired the folder event.
Message orginalMessage = e.getMessage();
//Get the folder the message is in.
Folder messageFolder = orginalMessage.getFolder();
//Is the new message in the Inbox?
if (messageFolder.getType() == Folder.INBOX)
{
//Check if the FolderListenerGUI is running.
if (folderListenerGUI != null)
{
//Grab the lock for the running FolderListenerGUI.
folderListenerGUI.invokeAndWait(new Runnable()
{
public void run()
{
//Call the NewMailArrived method to update the
//screen with a notification.
folderListenerGUI.NewMailArrived();
}
});
}
}
}
//Passes in reference to the FolderListenerGUI that is running.
public void setFolderListenerGUI(FolderListenerGUI folderGUI)
{
folderListenerGUI = folderGUI;
}
//Set the reference to the FolderListenerGUI to null
//(when it is shut down).
public void unsetFolderListenerGUI()
{
folderListenerGUI = null;
}
//Not used in this sample.
public void messagesRemoved(FolderEvent e)
{
}
}

1 comment:

  1. Hi R. K.

    I'm trying to implement a background listener with timers and I have come with several issues.
    First, the bg thread needs an instance of Application to be created in order to execute properly, so I have tryed to start the UI in the main function outside of the "startup" verification and then call setUIListener, do background app initialization with UIApp inside "startup" verification and only call app.enterEventDispatcher(); in the no "startup" part. So far so good. The app is pushed when device is started and the timertask is started and my background listener does what it has to do. But the UIapp is created again when the user enters the app using the alternate entry point. I don't know to also persist the UIApp created earlier.
    Second, the implementation needs to give the user the ability to stop/start the listener through the UI. As I am using timers for the background thread he only needs to call timer.cancel, but when he does that the ListenrApp dies. I think this is because there is no background thread to be run anymore. So i have tryed to start another timer that just call System.out.print("Idle") and goes to sleep for some time after the fist one is stopped so there is indeed a thread to be runned. Although the Listenrapp does not report to be dead now the backgorund thread does not seem to be working after the user leave the UI.
    I hope I have made myself understood.
    Thanks

    ReplyDelete

Place your comments here...