2 * Copyright (C) 2006 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 import android.util.Config;
20 import android.util.Printer;
23 * Class used to run a message loop for a thread. Threads by default do
24 * not have a message loop associated with them; to create one, call
25 * {@link #prepare} in the thread that is to run the loop, and then
26 * {@link #loop} to have it process messages until the loop is stopped.
28 * <p>Most interaction with a message loop is through the
29 * {@link Handler} class.
31 * <p>This is a typical example of the implementation of a Looper thread,
32 * using the separation of {@link #prepare} and {@link #loop} to create an
33 * initial Handler to communicate with the Looper.
36 * class LooperThread extends Thread {
37 * public Handler mHandler;
42 * mHandler = new Handler() {
43 * public void handleMessage(Message msg) {
44 * // process incoming messages here
53 private static final boolean DEBUG = false;
54 private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
56 // sThreadLocal.get() will return null unless you've called prepare().
57 private static final ThreadLocal sThreadLocal = new ThreadLocal();
59 final MessageQueue mQueue;
60 volatile boolean mRun;
62 private Printer mLogging = null;
63 private static Looper mMainLooper = null;
65 /** Initialize the current thread as a looper.
66 * This gives you a chance to create handlers that then reference
67 * this looper, before actually starting the loop. Be sure to call
68 * {@link #loop()} after calling this method, and end it by calling
71 public static final void prepare() {
72 if (sThreadLocal.get() != null) {
73 throw new RuntimeException("Only one Looper may be created per thread");
75 sThreadLocal.set(new Looper());
78 /** Initialize the current thread as a looper, marking it as an application's main
79 * looper. The main looper for your application is created by the Android environment,
80 * so you should never need to call this function yourself.
84 public static final void prepareMainLooper() {
86 setMainLooper(myLooper());
87 if (Process.supportsProcesses()) {
88 myLooper().mQueue.mQuitAllowed = false;
92 private synchronized static void setMainLooper(Looper looper) {
96 /** Returns the application's main looper, which lives in the main thread of the application.
98 public synchronized static final Looper getMainLooper() {
103 * Run the message queue in this thread. Be sure to call
104 * {@link #quit()} to end the loop.
106 public static final void loop() {
107 Looper me = myLooper();
108 MessageQueue queue = me.mQueue;
110 Message msg = queue.next(); // might block
115 if (msg.target == null) {
116 // No target is a magic identifier for the quit message.
119 if (me.mLogging!= null) me.mLogging.println(
120 ">>>>> Dispatching to " + msg.target + " "
121 + msg.callback + ": " + msg.what
123 msg.target.dispatchMessage(msg);
124 if (me.mLogging!= null) me.mLogging.println(
125 "<<<<< Finished to " + msg.target + " "
133 * Return the Looper object associated with the current thread. Returns
134 * null if the calling thread is not associated with a Looper.
136 public static final Looper myLooper() {
137 return (Looper)sThreadLocal.get();
141 * Control logging of messages as they are processed by this Looper. If
142 * enabled, a log message will be written to <var>printer</var>
143 * at the beginning and ending of each message dispatch, identifying the
144 * target Handler and message contents.
146 * @param printer A Printer object that will receive log messages, or
147 * null to disable message logging.
149 public void setMessageLogging(Printer printer) {
154 * Return the {@link MessageQueue} object associated with the current
155 * thread. This must be called from a thread running a Looper, or a
156 * NullPointerException will be thrown.
158 public static final MessageQueue myQueue() {
159 return myLooper().mQueue;
163 mQueue = new MessageQueue();
165 mThread = Thread.currentThread();
169 Message msg = Message.obtain();
170 // NOTE: By enqueueing directly into the message queue, the
171 // message is left with a null target. This is how we know it is
173 mQueue.enqueueMessage(msg, 0);
177 * Return the Thread associated with this Looper.
179 public Thread getThread() {
184 public MessageQueue getQueue() {
188 public void dump(Printer pw, String prefix) {
189 pw.println(prefix + this);
190 pw.println(prefix + "mRun=" + mRun);
191 pw.println(prefix + "mThread=" + mThread);
192 pw.println(prefix + "mQueue=" + ((mQueue != null) ? mQueue : "(null"));
193 if (mQueue != null) {
194 synchronized (mQueue) {
195 long now = SystemClock.uptimeMillis();
196 Message msg = mQueue.mMessages;
198 while (msg != null) {
199 pw.println(prefix + " Message " + n + ": " + msg.toString(now));
203 pw.println(prefix + "(Total messages: " + n + ")");
208 public String toString() {
210 + Integer.toHexString(System.identityHashCode(this))
214 static class HandlerException extends Exception {
216 HandlerException(Message message, Throwable cause) {
217 super(createMessage(cause), cause);
220 static String createMessage(Throwable cause) {
221 String causeMsg = cause.getMessage();
222 if (causeMsg == null) {
223 causeMsg = cause.toString();