Android Guts: Intro to Loopers and Handlers

Technorati verification code: X9YJQ6736KT3

One of the reasons I love Android API is because it contains so many useful little things. Many of them are not even specific to the platform and I really miss them in Java SE. Today I’d like to give a short introduction to two nice classes – Looper and Handler. They are used in Android UI internally, and available to us developers so we can do some cool things with their help.

So what can you do with Loopers and Handlers? Basically, they implement a common concurrency pattern that I call the Pipeline Thread. Here’s how it works:

  • The Pipeline Thread holds a queue of tasks which are just some units of work that can be executed or processed.
  • Other threads can safely push new tasks into the Pipeline Thread’s queue at any time.
  • The Pipeline Thread processes the queued tasks one after another. If there are no tasks queued, it blocks until a task appears in the queue.
  • Sometimes tasks can called messages and other names.

This architecture has some valuable traits and is widely used in frameworks and applications on different platforms.

In this post, we are going to build a simple app that emulates a queue of background downloads while showing its status in the UI. It will be based on a Pipeline Thread that we will build using Looper and Handler. As usual, the complete source is available at the bottom of the article.

But before we start, let’s discuss the Pipeline Thread for some more time and see how Looper and Handler implement it.

Usages of the Pipeline Thread

The most prominent usage of Pipeline Thread is found within almost any UI framework, including Swing (remember the event-dispatching thread?), SWT, Adobe Flex and, of course, Android Activities. The Pipeline Thread pattern is used to process UI events (such as button clicks, mouse movement, orientation changes, screen redraw and so on). This allows you to change a button caption without having to worry that the user will click the button at the same moment.

On the other hand, this forces you to only do quick operations in the UI thread – any developer knows what happens if you try to download a file right there in a button onClick handler. In our app we will overcome that by adding another Pipeline Thread and pushing long-lasting operations (in our case, the downloads) to it so that the UI thread can run free.

Other common usages of the Pipeline Thread pattern:

  • Executing requests to a remote service (usually you want to do them one by one and sequentially)
  • Uploading images to an HTTP service
  • Resizing and processing images (I once developed a picture uploader :) )
  • Downloading stuff, just like we’re going to do in our app

In general, using a Pipeline Thread rather than launching another thread for each background operation allows you to control the load and order (almost like law and order) of your background jobs. Also, you can have multiple Pipeline Threads and use them as a pool so you will have both the ability to execute multiple operations at once and keep the load under control.

In our example, we only want to allow one download at a time and we want downloads to execute in the order they were scheduled. Exactly the case to use a Pipeline Thread.

Looping and Handling

Looper is a class that turns a thread into a Pipeline Thread and Handler gives you a mechanism to push tasks into it from any other threads.

The Looper is named so because it implements the loop – takes the next task, executes it, then takes the next one and so on. The Handler is called a handler because someone could not invent a better name.

Here’s what you should put into a Thread‘s run() method to turn it into a Pipeline Thread and to create a Handler so that other threads can assign tasks to it:

	@Override
	public void run() {
		try {
			// preparing a looper on current thread
			// the current thread is being detected implicitly
			Looper.prepare();

			// now, the handler will automatically bind to the
			// Looper that is attached to the current thread
			// You don't need to specify the Looper explicitly
			handler = new Handler();

			// After the following line the thread will start
			// running the message loop and will not normally
			// exit the loop unless a problem happens or you
			// quit() the looper (see below)
			Looper.loop();
		} catch (Throwable t) {
			Log.e(TAG, "halted due to an error", t);
		}
	}

After that, you can just pass the handler to any other thread. It has a thread-safe interface that includes many operations, but the most straightforward ones are postMessage() and its relatives.

Note: The Handler interface has many more cool operations, especially related to message passing, that I will not cover in this example.

For example, imagine another thread has a reference to the handler that was created in our Pipeline Thread. Here’s how that other thread can schedule an operation to be executed in the Pipeline Thread:

		handler.post(new Runnable() {
			@Override
			public void run() {
				// this will be done in the Pipeline Thread
			}
		});

In our case, we will use this idiom to schedule download tasks to be performed (on the download pipeline thread) when the user clicks a button (which is handled on the UI thread). We will also use it the other way around – when the download thread notifies the activity that a download has completed (on the download thread), the activity will use a Handler that is attached to the UI thread to make sure that we update the UI on the UI thread only (which is a requirement of Android UI).

By the way, the UI thread has a Looper created for it implicitly, so you can just create a Handler in activity’s onCreate() and it will work fine:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // Create the Handler. It will implicitly bind to the Looper
        // that is internally created for this thread (since it is the UI thread)
        handler = new Handler();
    }

Implementation Details

If you understood the idea of Looper and Handler, the rest is details. Basically, I created a DownloadTask class that emulates a download task of a random duration. I did not want to do actual downloads because I didn’t want to eat your data plans, but it’s straightforward to change this into real work. Then, the DownloadThread has an interface that allows to enqueue DownloadTask instances and also to request it to exit gracefully. There is also the DownloadThreadListener interface that allows the download thread to notify some other entity about status updates. In our case, that interface will be implemented by the DownloadQueueActivity because we want to reflect the download progress in the UI.

At this point, however, we need to use another Handler – the one that is attached to the UI thread. The DownloadThreadListener is notified by the DownloadThread from the download thread itself, but the action we want to take (updating the progressbar and the textview) needs to be done from the UI thread. Therefore we use the UI handler like this:

	// note! this might be called from another thread
	@Override
	public void handleDownloadThreadUpdate() {
		// we want to modify the progress bar so we need to do it from the UI thread
		// how can we make sure the code runs in the UI thread? use the handler!
		handler.post(new Runnable() {
			@Override
			public void run() {
				// update the UI etc.
			}
		});
	}

Note: In case of doubt, it’s also OK to call a handler from its own thread.

Of course, you should read the code and the comments to understand things clearly.

Also, it’s better to do things like background downloads in a service, as described in my previous article.

Conclusion

Loopers and Handlers allow you to do cool things. However, they are related to concurrency which is often a slippery area. Be sure to ask your questions and give feedback in the comments – and to stay tuned for updates!

Attachment: the complete project source

Tags: , , , , , , , , , ,

38 Responses to “Android Guts: Intro to Loopers and Handlers”

  1. [...] This post was mentioned on Twitter by Richard Laksana, Brett Kisselbach. Brett Kisselbach said: Android Guts: Intro to Loopers and Handlers http://bit.ly/9PhAUn [...]

  2. [...] Mind The Robot » Android Guts: Intro to Loopers and Handlers [...]

  3. I am so grateful for your article post.Much thanks again. Will read on…

  4. Igor Buznitsky (immo) says:

    Thanks for this article and the project source with simple and clear explanation. Need to practice right now… :)

  5. Maxim Rahlis says:

    Thank you for a great clear article! this one is much better than google’s documentations

  6. Excellent blog, very useful, I’ll add it to my favorites. Regards

  7. [...] a Handler allows you to execute code in the UI thread. (To learn more about Handlers, you can read my article that discusses them in detail, and, of course the official Android [...]

  8. Manu says:

    Hi

    I tried to use Looper and Handler to create a thread. The thread listens for network messages (tcp) and also message from main activity over a looper.

    My problem is that looper.loop is blocking, so I can either listen for looper messages or network messages. Is there some ‘Select’ like option in Android where I can listen to multiple FDs?

    Surprisingly and as you also mentioned in your article, the main activity also has a handler but it is not blocking (we do not even need to call Looper.loop in main activity). Any idea how this works?

    thanks
    Manu

  9. ivan says:

    Hey Manu.

    Have a look at the ActivityThread code here:
    http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/java/android/app/ActivityThread.java;h=773c344bb3f69985a046c67ade9806b6c1d061a5;hb=HEAD
    If you scroll down to the bottom, you will see Looper.loop() invocation in main(). It’s called for us, we don’t need to call it in the activity.

    I am not sure that you chose the right architecture for your case. I don’t understand the goal very well so I can just point you to a good article that covers select-like functionality in Android (in fact, it comes from Java SE):
    http://onjava.com/pub/a/onjava/2002/09/04/nio.html

    However, I think you should just try to re-think your approach. Blocking sockets are simple to code and debug and sufficiently scalable for most apps. Maybe Handler/Looper are just not good for that case.

    -Ivan

  10. Congratulations for the good article. Bookmarked.

  11. ivan says:

    Glad you liked it Telmo.

  12. Amit Jain says:

    It was helpfull to me

  13. Матвей says:

    Спасибо за отличную статью. Но мне кажется что предложение, “Sometimes tasks can called messages and other names.” не совсем правильно. По http://developer.android.com/reference/android/os/Handler.html, обстановка другая, т.е., у MessageQueue ИЛИ Runnable ИЛИ Message.

  14. Matt J. says:

    How does the “Pipeline Thread” pattern differ from the “work queue processor pattern” mentioned in the online docs for Android’s IntentService?

  15. ivan says:

    Hey Matt.

    A Service has a different lifecycle than a thread. In a word, it’s “bigger”.

    You can have a handler thread to offload work within your Activity lifecycle, or within your Service. It’s a smaller scale pattern.
    A Service is handled by Android as a separate app component and can even run in a separate process, as you can understand from the other article you commented.
    The consequence is that for example it’s easier to share data between several threads of the same component (Activity or Service) but a separate Service has a more flexible lifecycle.

    Hope this made sense.

    -Ivan

  16. ivan says:

    Матвей,

    You can use the same Handler both to process Messages and to execute Runnables.
    Verified :)
    Also, check out the sources to see what exactly happens in the Handler/MessageQueue code.

    -Ivan

  17. Cesar G. says:

    Excellent article!! It is much more clearer than the android documentation I may say.

  18. ivan says:

    Glad you liked it Cesar.

  19. Ratan says:

    Wonderful!!! This is like sermon on mount, bringing big and complex thing to simple and easy to understand concepts

  20. ivan says:

    That’s a bit too great a comparison but thank you anyway Ratan :)

  21. WarrenFaith says:

    Hi,
    I have a game thread which needs to inform the activity to show a popup. After working with your sample and while I tried to implement your sample in my game, I stripped it down to the listener only.
    So my thread has a reference to the listener which is implemented by the activity. I simply call the method of the listener and the activity do whatever I implemented in the method body… in my case the Dialog.

    Can you explain me, why I should try to work with handler and pipeline when I could simply call a self made listener?

    Greetings Martin

  22. ivan says:

    Hey Martin.

    As far as I understand, your listener gets called in the “game” thread.
    You are not allowed to do UI manipulations in any thread other than the UI thread. Thus the need to do it with Handlers.

    -Ivan

  23. [...] both application activities and also its services but this will be subject for another post (android.os.Looper and Handler are worth mentioning too). Getting back to the reason for the [...]

  24. kollins says:

    As far as I understand, your listener gets called in the “game” thread.
    You are not allowed to do UI manipulations in any thread other than the UI thread. Thus the need to do it with Handlers.

  25. David Cheney says:

    Hey Ivan,

    First, thanks very much for your article, I found it to be one of very few truly helpful looks at Handler etc.

    For another take on the subject, after reading Ivan’s post I took a look at the Android source and came up with Multitasking in Android. I hope it helps somebody, and invite feedback.

    Dave

  26. [...] addition, if you did not read the article on Handler, please do so. Although it does not cover messaging per se, it gives you understanding of the [...]

  27. Milen Dimitrov says:

    What is the battery usage when we implement this against “normal” thread use ?

  28. ivan says:

    Milen,

    If battery usage is critical for you, then I suggest that you do some benchmarking using a test case as close to your production code as possible.

    -Ivan

  29. Michael says:

    Hi Ivan,

    Thanks for the great article – I’ve been investigating on the various means for creating pipeline threads and have only come across one other way – at least one that’s so far worked for me!

    http://www.anddev.org/post90900.html#p90900

    I tried dissecting your example into something else – especially to attempt to yield similar results but with less code….achieved #epicfail on my part however. Also it seems there is no way around the use of a Listener on your part (custom interface) to achieve this?

    This was another means of doing something similar – http://codinghard.wordpress.com/2009/05/16/android-thread-messaging/ – dubugging this shows a single parallel thread continuing to persist; although it doesn’t have all the overhead to manage and track assigned tasks (queue) etc.

    Would greatly appreciate your response – my email is mike@bsodmike.com

    Cheers,
    Mike

  30. ivan says:

    Hi Mike.

    Could you please describe your case better so I can understand what you’re aiming to do?

    -Ivan

  31. [...] example is largely based on Ivan’s code; I cut it down into a far more generic model that’s easier to digest. It sets up a single [...]

  32. Michael says:

    Hi Ivan,

    I worked through your demo (my tweaked source) and extended this code of mine to implement pipelining.

    Question: I take it, all Listeners (Interfaces), are created as separate .java files by default?

    Source @Github

    Cheers, Mike.

  33. ivan says:

    Mike,

    It’s an interface so any class can implement it and the need to create a separate class is not always there.

    In addition, you can have anonymous classes that do not require a separate code file.

    -Ivan

  34. [...] addition, if you did not read the article on Handler, please do so. Although it does not cover messaging per se, it gives you understanding of the [...]

  35. [...] Here’s what you should put into a Thread‘s run() method to turn it into a Pipeline Thread and to create a Handler so that other threads can assign tasks to it: ? [...]

  36. vishwesh says:

    downloaded the code and try to call a webservice as a Task in place of DownloaderTask. I have enque my task from onCreate method and it works fine and populate the list from service. And now I go back by pressing BACK button and recreate my activity now it gives NullPointerException at DownloaderThread’s enque method on Handler line. Please help me.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>