summaryrefslogtreecommitdiffstats
path: root/core/java/android/os/Looper.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/os/Looper.java')
-rw-r--r--core/java/android/os/Looper.java214
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;
+ }
+ }
+}
+