diff options
Diffstat (limited to 'core/java/android/os/Looper.java')
-rw-r--r-- | core/java/android/os/Looper.java | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java new file mode 100644 index 0000000..80b68e2 --- /dev/null +++ b/core/java/android/os/Looper.java @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import android.util.Config; +import android.util.Printer; + +/** + * Class used to run a message loop for a thread. Threads by default do + * not have a message loop associated with them; to create one, call + * {@link #prepare} in the thread that is to run the loop, and then + * {@link #loop} to have it process messages until the loop is stopped. + * + * <p>Most interaction with a message loop is through the + * {@link Handler} class. + * + * <p>This is a typical example of the implementation of a Looper thread, + * using the separation of {@link #prepare} and {@link #loop} to create an + * initial Handler to communicate with the Looper. + * + * <pre> + * class LooperThread extends Thread { + * public Handler mHandler; + * + * public void run() { + * Looper.prepare(); + * + * mHandler = new Handler() { + * public void handleMessage(Message msg) { + * // process incoming messages here + * } + * }; + * + * Looper.loop(); + * } + * }</pre> + */ +public class Looper { + private static final boolean DEBUG = false; + private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; + + // sThreadLocal.get() will return null unless you've called prepare(). + private static final ThreadLocal sThreadLocal = new ThreadLocal(); + + final MessageQueue mQueue; + volatile boolean mRun; + Thread mThread; + private Printer mLogging = null; + private static Looper mMainLooper = null; + + /** Initialize the current thread as a looper. + * This gives you a chance to create handlers that then reference + * this looper, before actually starting the loop. Be sure to call + * {@link #loop()} after calling this method, and end it by calling + * {@link #quit()}. + */ + public static final void prepare() { + if (sThreadLocal.get() != null) { + throw new RuntimeException("Only one Looper may be created per thread"); + } + sThreadLocal.set(new Looper()); + } + + /** Initialize the current thread as a looper, marking it as an application's main + * looper. The main looper for your application is created by the Android environment, + * so you should never need to call this function yourself. + * {@link #prepare()} + */ + + public static final void prepareMainLooper() { + prepare(); + setMainLooper(myLooper()); + if (Process.supportsProcesses()) { + myLooper().mQueue.mQuitAllowed = false; + } + } + + private synchronized static void setMainLooper(Looper looper) { + mMainLooper = looper; + } + + /** Returns the application's main looper, which lives in the main thread of the application. + */ + public synchronized static final Looper getMainLooper() { + return mMainLooper; + } + + /** + * Run the message queue in this thread. Be sure to call + * {@link #quit()} to end the loop. + */ + public static final void loop() { + Looper me = myLooper(); + MessageQueue queue = me.mQueue; + while (true) { + Message msg = queue.next(); // might block + //if (!me.mRun) { + // break; + //} + if (msg != null) { + if (msg.target == null) { + // No target is a magic identifier for the quit message. + return; + } + if (me.mLogging!= null) me.mLogging.println( + ">>>>> Dispatching to " + msg.target + " " + + msg.callback + ": " + msg.what + ); + msg.target.dispatchMessage(msg); + if (me.mLogging!= null) me.mLogging.println( + "<<<<< Finished to " + msg.target + " " + + msg.callback); + msg.recycle(); + } + } + } + + /** + * Return the Looper object associated with the current thread. + */ + public static final Looper myLooper() { + return (Looper)sThreadLocal.get(); + } + + /** + * Control logging of messages as they are processed by this Looper. If + * enabled, a log message will be written to <var>printer</var> + * at the beginning and ending of each message dispatch, identifying the + * target Handler and message contents. + * + * @param printer A Printer object that will receive log messages, or + * null to disable message logging. + */ + public void setMessageLogging(Printer printer) { + mLogging = printer; + } + + /** + * Return the {@link MessageQueue} object associated with the current + * thread. + */ + public static final MessageQueue myQueue() { + return myLooper().mQueue; + } + + private Looper() { + mQueue = new MessageQueue(); + mRun = true; + mThread = Thread.currentThread(); + } + + public void quit() { + Message msg = Message.obtain(); + // NOTE: By enqueueing directly into the message queue, the + // message is left with a null target. This is how we know it is + // a quit message. + mQueue.enqueueMessage(msg, 0); + } + + public void dump(Printer pw, String prefix) { + pw.println(prefix + this); + pw.println(prefix + "mRun=" + mRun); + pw.println(prefix + "mThread=" + mThread); + pw.println(prefix + "mQueue=" + ((mQueue != null) ? mQueue : "(null")); + if (mQueue != null) { + synchronized (mQueue) { + Message msg = mQueue.mMessages; + int n = 0; + while (msg != null) { + pw.println(prefix + " Message " + n + ": " + msg); + n++; + msg = msg.next; + } + pw.println(prefix + "(Total messages: " + n + ")"); + } + } + } + + public String toString() { + return "Looper{" + + Integer.toHexString(System.identityHashCode(this)) + + "}"; + } + + static class HandlerException extends Exception { + + HandlerException(Message message, Throwable cause) { + super(createMessage(cause), cause); + } + + static String createMessage(Throwable cause) { + String causeMsg = cause.getMessage(); + if (causeMsg == null) { + causeMsg = cause.toString(); + } + return causeMsg; + } + } +} + |