There’s a lot of confusion on this, so I’ll lay it all out. There’s not much to it, so this will be pretty quick and painless, I promise!
The BlackBerry UI API (net.rim.device.api.ui.*) is not thread safe. If you’re a Swing developer, this will seem like second nature, and at best you’ll need to skim the rest of this post. If you’re used to pure MIDP (javax.microedition.lcdui) or AWT though - pay attention!
Event Thread
Each BlackBerry application has one event thread. You’re given this thread by the OS when your application starts (it’s the thread that enters your main method). You start your application’s event processing by doing something like this:
public class MyApp extends UiApplication
{
// ...
public static void main(String[] args) {
MyApp app = new MyApp();
app.enterEventDispatcher()
}
That enterEventDispatcher call starts the message pump that will deliver user input to your application.
The Golden Rule
The golden rule of the single-threaded API model is:
Only the event thread can modify the user interface.
In fact, it’s a little more subtle - only a thread holding the user interface event lock can modify the user interface - more on that later, for now just know that almost always the event thread is the one holding that event lock.
This means, if you’re doing anything that will directly result in immediate changes to the UI - pushing (or removing) screens onto the display stack, modifying the visible state of your UI components, painting - you have to do it in the event thread.
Simple, right? Yes, in theory. In practice, it’s not much more difficult - just bear in mind a couple of things.
As I said above the thread that enters your main method is your application’s event thread. This, combined with the golden rule means that in the initial call to your main method, you can do all the UI work you want. Often you create your app’s initial screen and push it onto the stack (using UiApplication.pushScreen) there - or at least in a method that you call directly from there. However, at some point you want to call enterEventDispatcher or you’ll never get user input. How do you modify the UI after that?
Modifying the UI
Now, the golden rule doesn’t mean that you can’t call any methods on any UI component from any other thread. Anything that gets information (EditField.getText for example) is fine. Also fine is setting information that may not result in immediate changes. But for most of the built-in UI components - like EditField, or LabelField, methods like setText will result in a change and so must be done while you have the event lock.
How do I know I’m on the event thread
Easy - just UiApplication.getUiApplication().isEventThread() (or isEventDIspatchThread, which is a static method and does the same thing - both of those methods, by the way, actually reside in net.rim.device.api.system.Application, which is UiApplication’s super class).
You will sometimes end up on the event thread - menu items are executed on the event thread for example.
How can I modify my UI?
There are two ways:
1. Use the net.rim.device.api.system.Application methods invokeLater or invokeAndWait - both of which take a Runnable. Anything in that Runnable’s run method will be executed by the event thread at the next available opportunity. The first method is asynchronous (which means in this case that it returns immediately) the second is synchronous (so waits until your Runnable’s run method is finished before returning).
2. Get the event lock -
synchronized(UiApplication.getUiApplication().getEventLock())) {
// UI Code here
}
This is what I mentioned earlier - the golden rule is really about the event lock, not the event thread. Now, this method may seem simpler, but because you’re doing a manual lock, there’s a greater chance for accidentally deadlocking the event thread (which is a bad thing), and method 1 is usually a safer bet
Pretty much that’s all you’ll need to know, except for one thing:
The second golden rule
Minimize processing time while holding the event lock.
Since there’s only one thread doing UI updates and receiving user input, blocking it for long periods of time will make your application appear sluggish and unresponsive. Better to do as much heavy lifting as possible in another thread and only use the event thread sparingly. This means that anything you pass into invokeLater or invokeAndWait (or in your synchronized block) had better do its thing and finish pretty fast.
Specifically - and this is important enough to be worth stating explicitly - never do any networking on the event thread. At best (depending on the type of connection) this will result in massive slowdowns, at worst it will actually crash your application. Remember what I said earlier about menu items being executed on the event thread? Well, now you can imagine why the following is a bad idea:
menu.add(new MenuItem("Connect", 10, 10) {
public void run() {
//NEVER DO THIS !!!
HttpConnection connection = (HttpConnection)Connector.open("http://www.thinkingblackberry.com");
connection.openInputStream();
}
});
The correct way is something more like this:
class NetworkConnector extends Thread {
public void run() {
HttpConnection connection = (HttpConnection)Connector.open("http://www.thinkingblackberry.com");
connection.openInputStream();
}
}
// ...
menu.add(new MenuItem("Connect", 10, 10) {
public void run() {
NetworkConnector nwc = new NetworkConnector();
nwc.start();
}
});
So that’s all you need to know - as promised, pretty quick and painless. Remember the golden rules and you’ll have no problems!






14 Responses
Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.
Hey Anthony,
Not sure where to post this comment but I’ll try here. I’m trying to implement a real-time clock on my app, situated at the title bar. I’m right now using currentTime = new DateField(”", System.currentTimeMillis(), DateField.TIME) but it does not refresh by itself, it just displays the time that it was open. I saw something about RealTimeClockListener() but there wasn’t much help about it, and im not sure how to use this (if this is even the right thing to use). Can you help me out?
BTW for future reference, can I ask questions through the comment posts, or would you prefer emails? And where should people post?
Thanks
Hi Andrew,
Questions through comment posts are good - I’m trying to build up the content of the site, and seeing other questions might be useful to other users.
For the real-time clock you’d need to have a separate thread that updates the time in the date field. This is actually related to this article, as the setDate method needs to be called in event thread, so your time-update thread would just do something like this over and over again:
UiApplication.getUiApplication().invokeLater() { new Runnable { public void run() { dateField.setDate(System.currentTimeMillis()); } }Anthony
Great, thanks Anthony! =D
Hi Anthony
I didn’t really understand the concept of invokeLater and how to use it in my scenario. I want to do some processing in my MainScreen (copying large files etc) and once that is done, I want to push another MainScreen.
Now I really don’t understand (and I am totally confused right now) of where I will copy the files and how I call pushScreen and which of these are present in the invokeLater runnable. Plese help!
I’ll like to know how to stop a loop and gain focus on screen, i need that a ENTER key press to continue the loop, do you know something about that? thanks ( sorry about my english )
for more information i have a for() loop and in this for i havo to ask for some numbers and then press enter to continue looping
hey i getting o/p totally,not in a time interval,can u guys help me
In the main class i did this
Root r=new Root();
r.enterEventDispatcher();
pushScreen(new macca());
————————–
class macca extends MainScreen implements Runnable
{
LabelField ss[]=new LabelField[5];
macca()
{
th=new Thread(this);
th.start();
}
public void run()
{
UiApplication.getUiApplication().invokeAndWait(new Runnable() {
public void run()
{
synchronized(Application.getEventLock())
{
for(int i=0;i<5;i++)
{
ss[i]=new LabelField(”ds”);
add(ss[i]);
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
});
}
I want labelfield to display one after other in time intervals
Regarding your recent post about what topics readers would be interested in, I would interested in learning more about your last point here (about HTTP connections and threads). I’m building a BlackBerry client for a web service. I have a class WebApiClient with a number of methods that reflect those exposed by the web service API (e.g., createUser(), updatePost(), etc). I am trying to implement a single fetch() method that all of these methods can use to perform an actual HTTP request once they have set up the appropriate URL/headers, and which would do so in a new thread for the reasons discussed above. My principal question is how best to return the result (i.e., HTTP response headers and body) of the fetch request to the original thread. Using your last example above, at line 13, the event thread starts the network connector thread. So, for example:
class WebAPIClient {
public String getComments(String postId) {
String url = "http://webservice.com/posts/" + postId + "/comments/";
return fetch(url);
}
public String getPosts() {
String url = "http://webservice.com/posts/";
return fetch(url);
}
private String fetch(String url) {
(new Thread(new Runnable( ) {
public void run( ) {
HttpConnection c = (HttpConnection)Connector.open(url);
c.getResponseCode( );
// get the response text, etc., but then how to return it to getPosts()???
}
})).start( );
}
}
Should a callback or listener be used? I assume this is well-worn ground, but I am new to Java. I would be grateful for your thoughts on how best to implement something like this.
Thanks
Why do I get a —event thread not running— message on my blackberry???? While I’m waiting for a youtube video to load???!!! Please help!
hi, anthony
i have a little confusion, does invokeLater or invokeAndWait start a new thread?
@Jihgshan - neither one starts a new thread. They queue up a Runnable which is run on the event thread. You can invoke them from a different thread, or even from the event thread itself - though running invokeAndWait on the event thread would result in a deadlock (or maybe a RuntimeException, if the API checks for something like that)
Hey, this is a great tutorial, but I have a question on the UI updates possible via non-UI threads. I was checking out this short video tutorial on YouTube(http://www.youtube.com/watch?v=d8jXNYzUkuI), and it seems the user invoked a setText() method on a LabelField without either obtaining the event lock, or using the invokeLater / invokeAndWait methods.
In the video around the 1:25 mark, you can see the user has the following line in his UpdateThread class…
m_pTextField.setText( …. );
He mentioned he needed to queue the Dialog.alert part up to the Event Thread in order for that to work, but didn’t mention anything about this setText() method. How did this work?
hi,
i want to know whether HttpConnection creates new thread in Blackberry,
wht d prob is i m writting a code for video recording more thn one clips and thn snding it on to d server,
but dont know why before sending 1st file to server,it strts asking for second thread,
m not using any seperate thread for sending file to server while it is is same thread,where recording is.
so can u help me out.
thnks
Neha
B Mac question is very relevant! I’m asking myself the same question… how can he use .setText via a non-UI threads?