Free Trial

Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.


  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • DownloadDownload
  • PrintPrint
Share this Page URL
Help

4. Acquiring Data > The Main Thread

The Main Thread

The Android operation system has exactly one blessed thread authorized to change anything that will be seen by the user. This alleviates what could be a concurrency nightmare, such as view locations and data changing in one thread while a different one is trying to lay them out onscreen. If only one thread is allowed to touch the user interface, Android can guarantee that nothing vital is changed while it’s measuring views and rendering them to the screen. This has, unfortunately, serious repercussions for how you’ll need to acquire and process data. Let me start with a simple example.

You There, Fetch Me that Data!

Were I to ask you, right now, to download an image and display it to the screen, you’d probably write code that looks a lot like this:

public void onCreate(Bundle extra){
try{
       URL url = new URL("http://wanderingoak.net/bridge.png");
       HttpURLConnection httpCon =
           (HttpURLConnection)url.openConnection();
       if(httpCon.getResponseCode() != 200)
       throw new Exception("Failed to connect");
       InputStream is = httpCon.getInputStream();
       Bitmap bitmap = BitmapFactory.decodeStream(is);
       ImageView iv = (ImageView)findViewById(R.id.main_image);
       if(iv!=null)
           iv.setImageBitmap(bitmap);
    }catch(Exception e){
    Log.e("ImageFetching","Didn't work!",e);
    }
}

This is exactly what I did when initially faced with the same problem. While this code will fetch and display the required bitmap, there is a very sinister issue lurking in the code—namely, the code itself is running on the main thread. Why is this a problem? Consider that there can be only one main thread and that the main thread is the only one that can interact with the screen in any capacity. This means that while the example code is waiting for the network to come back with image data, nothing whatsoever can be rendered to the screen. This image-fetching code will block any action from taking place anywhere on the device. If you hold the main thread hostage, buttons will not be processed, phone calls cannot be answered, and nothing can be drawn to the screen until you release it.

Watchdogs

Given that a simple programmer error (like the one in the example code) could effectively cripple any Android device, Google has gone to great lengths to make sure no single application can control the main thread for any length of time. Hogging too much of the main thread’s time will result in this disastrous dialog screen (Figure 4.1) showing up over your application.

Figure 4.1. What the user sees when you hold the main thread hostage.

Image

Tracking Down ANR crashes

Anytime you see an ANR crash, Android will write a file containing a full stack trace. You can access this file with the following ADB command line: adb pull/data/anr/traces.txt. This should help you find the offending line. The traces.txt file shows the stack trace of every thread in your program. The first thread in the list is usually the one to look at carefully. Sometimes, the long-running blocking operation will have completed before the system starts writing traces.txt, which can make for a bewildering stack trace. Your long-running operation probably finished just after Android started to get huffy about the main thread being delayed. In the example code that displays the image, however, it will probably show that httpCon.getResponseCode() was the culprit. You’ll know this because it will be listed as the topmost stack trace under your application’s thread list.


This dialog is unaffectionately referred to by developers as an ANR (App Not Responding) crash. Although operations will continue in the background, and the user can press the Wait button to return to whatever’s going on within your application, this is catastrophic for most users, and you should avoid it at all costs.

What Not to Do

What kind of things should you avoid on the main thread?

• Anything involving the network

• Any task requiring a read or write from or to the file system

• Heavy processing of any kind (such as image or movie modification)

• Any task blocking a thread while you wait for something to complete

Excluding this list, there isn’t much left, so, as a general rule, if it doesn’t involve setup or modification of the user interface, don’t do it on the main thread.

When Am I on the Main Thread?

Anytime a method is called from the system (unless explicitly otherwise stated), you can be sure you’re on the main thread. Again, as a general rule, if you’re not in a thread created by you, it’s safe to assume you’re probably on the main one, so be careful.