Wink Saville’s Blog

December 11, 2007

Andriod – How do Service, Handler and Loopers work

Filed under: Android, programming — wink @ 10:10 pm

I was looking at ServiceStartArguments.java beneath the android samples directory and wondering how a Service gets its messages. So I thought I’d dissect ServiceStartArguments.java to learn.

The code extends Service and implements Runnable. Because it extends Service its onCreate() is invoked once for the life time of the service when the first Context.startService() is called. Then Context.startService invokes onStart() as defined by a Services Lifecycle. In ServiceStartArguments.onCreate() instantiates a new Intent() which is used when sending notifications in the handler. It also creates and starts a Java Thread.

Next onStart() and run() will be called, but you have no idea the order so we see that in onStart() looping waiting for mServiceHandler to be created by run(). After which it can gets a message (obtainMessage()) which has its target field set to itself and thus sends the startId and arguments to itself.

In run() frist calls Looper.prepare() this is a factory method which creates the one and only Looper for this thread. The Looper() constructor creates the threads MessageQueue and then Looper.myLooper() returns the Looper instance created by prepare().

When I first looked at this code I couldn’t figure how myLooper() worked as there was no parameter. Typically, a factory method like this would return an ID which I would have expected to be passed as a parameter to myLooper() but that wasn’t the case. Instead the Looper() instance is stored as a ThreadLocal<> variable and hence is always available. This also means Looper doesn’t needs dynamic arrays to manage an unknown number of Looper’s, nice.

Next, run() creates the ServiceHandler which extends Handler and then calls Looper.loop() which loops getting a message via MessageQueue.next() and dispatching via dispatchingMessage(). Looper.loop() terminates if a message is null, Message.target is null or there is an exception.

An important item is that Handler.obtainMessage() needs to know the its own messageQueue, which is in the Looper. This is accomplished by Looper being created before Handler and then Handler can use the Looper.myLooper() to retrieve the threads Looper from the ThreadLocal<> storage.

So in review, an Android service is has-a MessageQueue created by a Looper and one or more Handlers which are the targets of messages. A Handler has an associated Looper either directly associated in the handler constructor or implicitly associated by the Looper associated with the service’s thread.

No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress