Using threads for basic tasks on the Blackberry is not necessarily as difficult as it may first appear. You can leverage RIM's net.rim.device.api.system.Application class to synchronize with the EventLock and perform whatever tasks your threading model requires. Of course when programming games or intricate UI component interaction using threads can be complex and downright challenging. Thankfully, for most apps you're likely to do simple threading tasks that don't require such interaction. In order to modify UI components you must perform all the work within the UI thread and there are two general rules that you'll have to follow:
1) Modify UI components using the invokeLater() method, 2)Never call an HTTP request within the UI thread.

The invokeLater() method is used when changes are made to the UI outside of the main UI thread. It places your runnable object into your application's main event queue and is processed after all events pending in the main queue are complete. In other words, it's similar to regular Java threads where you use the join() method so your code waits for other threads to complete before grabbing the eventlock. Making HTTP requests within the UI thread will most assuredly make your application slow down and could make it crash. Instead of using invokeLater() or other methods to grab the UI thread you'll want to do something like the following:

new Thread(){
public void run(){
HttpConnection http_con = (HttpConnection)Connector.open("http://berrytutorials.blogspot.com");
}
}.start();



Here we're creating a new thread that opens the HTTP connection but it will run as a background process and not tie up system resources on the main UI thread. For more details on opening HTTP check out the HTTPDemo included in the RIM samples that are part of your component pack download for Eclipse.

Background


For the example we'll be using the code from a previous tutorial on Listfields and will modify it to make updates to the list from a thread. Take a few minutes to read through that code, copy it and place it into a new Blackberry project in Eclipse - otherwise you can get the sample code in it's entirety here.

Thread.sleep() will be used to simulate your code performing data processing or making an HTTP connection that will occur in the background of the app. Once that's complete the listfield will be updated with a simple string that will include the thread name and an element number that is incremented for each update so you can see the thread working. It wouldn't take much modification to modify the code below and, for example, make a connection to Twitter via their API to grab updates to the people you follow, then update the list with that content.

You might ask, "How does the ListField know when to update itself?" - what I'm doing in the code is leveraging the Observer design pattern to attach the ListField as a "observer" to the Thread we create. It will "listen" to the Thread until it's notified of an update and then will add the new message to the list and redraw itself. Here's an image that will serve to give you an overview of what the Observer pattern is doing, courtesy of javaworld.com:




For the sample code, the Subject shown in the image above will be the Thread we create and the Observer is the ListField itself - once the Thread has slept (simulating the HTTP connection or data processing task) it will notify the Listfield of the change. To do this appropriately we'll create an interface for the ListField to implement containing the update() method and will create the addObserver(), removeObserver() and notifyObservers() methods in the Thread class. The reason we use the interface here is that many different Classes might need to observe the Thread's progress and could be attached as Observers. The Thread loops through the attached Observers and informs them of the changes via the the update() method. The end result will be a ListField that auto updates elements every 10 seconds as in the screenshot below:



In this sample we don't necessarily have to use the interface since we're only attaching one Observer but it's good practice to see how it works. If you're not familiar with the Observer pattern take a few minutes and read through the following links: Background on Design Patterns GangofFour - Observer Pattern, PDF on Observer Pattern

Subject Code - Create the Thread


First we need to add a private class that is used to implement the Thread itself. Following the Observer pattern we'll add the methods 'addObserver(MyListField mlf)' and 'removeObserver(MyListField mlf)' that permit the thread to add/remove Observers to itself and a 'notifyObservers()' function that will inform observers that are attached to the Thread that a change has occurred. Here's the code:


//Runnable class
private class CheckForUpdates implements Runnable{

private String updatedMessage;
private Vector observers;

public CheckForUpdates(){
observers = new Vector();
}

//Attach the observer to the class
public void addObserver(MyListField mlf){
observers.addElement(mlf);
}

//Not used for this example - remove an observer
public void removeObserver(MyListField mlf){
observers.removeElement(mlf);
}

//Go through vector of observers and call update on them
//Sending the updatedMessage String.
public void notifyObservers(){
for(int i=0;i ((MyListField)observers.elementAt(i)).update(updatedMessage);
}
}

//Overridden runnable method. Simulates checking external resource(such as HTTP call to remote server)
//using the sleep() method then changes the message and notifies the attached observers.
public void run(){
int counter = 0;
try{
while(true){
//Simulate an HTTP connection OR data processing
Thread.sleep(10000);
counter++;
updatedMessage = Thread.currentThread().getName() + "- Element " + Integer.toString(counter);
notifyObservers();
}
}

//Simply return if interrupted.
catch (InterruptedException e){
return;
}
}


}



Note that we're creating a private Vector to hold the observers that are attached to the instance of the thread although there will be only one observer for the example. Additionally, if you take a look at the run() method, you'll see that we loop indefinitely, calling Thread.sleep(10000) and when the Thread wakes it increments the counter, updates the message to pass to the observers, and calls the 'notifyObservers()' method. If this were production you'd want to add some code that can stop the Thread based on a keystroke, menu option, or some other method, otherwise it will eventually consume all the resources available.

Observer Code - Create the Interface and Update Method


The next step is to create the Observer interface and the update() method, in this case contained in the MyListField class. Here's the code:


public interface ObserverInterface{

public void update(String message);
}

....
private class MyListField extends ListField implements ObserverInterface{
.....
.....
.....
//Update function takes in a message to add to the list,
//inserts it into the list, and calls invalidate to repaint the list
public void update(final String message){
final int i = this.getSize();
final ListCallback mlc = (ListCallback)this.getCallback();
final MyListField mlf = this;
UiApplication.getUiApplication().invokeLater(new Runnable(){
public void run(){
mlf.insert(i);
mlc.insert(message,i);

}
});


}



The update() method grabs the UiApplication event lock by calling 'invokeLater()' with a new Runnable() where we insert the String into the List. Thus, the main UI thread will complete whatever functions it's performing and pass the lock to our thread which updates the List and redraws it to the screen.

Constructor code


Finally, add the following to the constructor of the ListFieldTest class:

//Declare the Runnable Thread
CheckForUpdates cfu = new CheckForUpdates();

//Attach the Observer - in this case myList is the observer
cfu.addObserver(myList);

//Declare a new thread with our Runnable as input and start thread
Thread t = new Thread(cfu);
t.start();



That's all there is to it. We create an instance of our Thread, attach the List as an Observer so the thread can call the List's update() function when there's a change, and simply start the thread. Side Note: Java has Observer/Observable as part of the language specification however RIM does not and as a result you can't leverage the code that's already out there. Nonetheless, implementing the pattern wasn't too difficult, at least for this simple example, and understanding how design patterns work will really make life easier.

6 comments:

Unknown said...

John, this is exactly the information I was looking for. This is a really great post. Thank you for writing it.

John Banks said...

You're welcome Sean, glad it helped you out!

Hades said...

damn nice man

Anonymous said...

Excelente codigo.
Graciela...! (Thanks)

sujith ravindran said...

good work .. really made it easy to understand

ABY said...

what should i do only to update an element in the list.

Post a Comment

top