OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / frameworks / base / core / java / android / os / Looper.java
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package android.os;
18
19 import android.util.Config;
20 import android.util.Printer;
21
22 /**
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.
27   * 
28   * <p>Most interaction with a message loop is through the
29   * {@link Handler} class.
30   * 
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.
34   * 
35   * <pre>
36   *  class LooperThread extends Thread {
37   *      public Handler mHandler;
38   *      
39   *      public void run() {
40   *          Looper.prepare();
41   *          
42   *          mHandler = new Handler() {
43   *              public void handleMessage(Message msg) {
44   *                  // process incoming messages here
45   *              }
46   *          };
47   *          
48   *          Looper.loop();
49   *      }
50   *  }</pre>
51   */
52 public class Looper {
53     private static final boolean DEBUG = false;
54     private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
55
56     // sThreadLocal.get() will return null unless you've called prepare().
57     private static final ThreadLocal sThreadLocal = new ThreadLocal();
58
59     final MessageQueue mQueue;
60     volatile boolean mRun;
61     Thread mThread;
62     private Printer mLogging = null;
63     private static Looper mMainLooper = null;
64     
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
69       * {@link #quit()}.
70       */
71     public static final void prepare() {
72         if (sThreadLocal.get() != null) {
73             throw new RuntimeException("Only one Looper may be created per thread");
74         }
75         sThreadLocal.set(new Looper());
76     }
77     
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.
81      * {@link #prepare()}
82      */
83      
84     public static final void prepareMainLooper() {
85         prepare();
86         setMainLooper(myLooper());
87         if (Process.supportsProcesses()) {
88             myLooper().mQueue.mQuitAllowed = false;
89         }
90     }
91
92     private synchronized static void setMainLooper(Looper looper) {
93         mMainLooper = looper;
94     }
95     
96     /** Returns the application's main looper, which lives in the main thread of the application.
97      */
98     public synchronized static final Looper getMainLooper() {
99         return mMainLooper;
100     }
101
102     /**
103      *  Run the message queue in this thread. Be sure to call
104      * {@link #quit()} to end the loop.
105      */
106     public static final void loop() {
107         Looper me = myLooper();
108         MessageQueue queue = me.mQueue;
109         while (true) {
110             Message msg = queue.next(); // might block
111             //if (!me.mRun) {
112             //    break;
113             //}
114             if (msg != null) {
115                 if (msg.target == null) {
116                     // No target is a magic identifier for the quit message.
117                     return;
118                 }
119                 if (me.mLogging!= null) me.mLogging.println(
120                         ">>>>> Dispatching to " + msg.target + " "
121                         + msg.callback + ": " + msg.what
122                         );
123                 msg.target.dispatchMessage(msg);
124                 if (me.mLogging!= null) me.mLogging.println(
125                         "<<<<< Finished to    " + msg.target + " "
126                         + msg.callback);
127                 msg.recycle();
128             }
129         }
130     }
131
132     /**
133      * Return the Looper object associated with the current thread.  Returns
134      * null if the calling thread is not associated with a Looper.
135      */
136     public static final Looper myLooper() {
137         return (Looper)sThreadLocal.get();
138     }
139
140     /**
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.
145      * 
146      * @param printer A Printer object that will receive log messages, or
147      * null to disable message logging.
148      */
149     public void setMessageLogging(Printer printer) {
150         mLogging = printer;
151     }
152     
153     /**
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.
157      */
158     public static final MessageQueue myQueue() {
159         return myLooper().mQueue;
160     }
161
162     private Looper() {
163         mQueue = new MessageQueue();
164         mRun = true;
165         mThread = Thread.currentThread();
166     }
167
168     public void quit() {
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
172         // a quit message.
173         mQueue.enqueueMessage(msg, 0);
174     }
175
176     /**
177      * Return the Thread associated with this Looper.
178      */
179     public Thread getThread() {
180         return mThread;
181     }
182     
183     /** @hide */
184     public MessageQueue getQueue() {
185         return mQueue;
186     }
187     
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;
197                 int n = 0;
198                 while (msg != null) {
199                     pw.println(prefix + "  Message " + n + ": " + msg.toString(now));
200                     n++;
201                     msg = msg.next;
202                 }
203                 pw.println(prefix + "(Total messages: " + n + ")");
204             }
205         }
206     }
207
208     public String toString() {
209         return "Looper{"
210             + Integer.toHexString(System.identityHashCode(this))
211             + "}";
212     }
213
214     static class HandlerException extends Exception {
215
216         HandlerException(Message message, Throwable cause) {
217             super(createMessage(cause), cause);
218         }
219
220         static String createMessage(Throwable cause) {
221             String causeMsg = cause.getMessage();
222             if (causeMsg == null) {
223                 causeMsg = cause.toString();
224             }
225             return causeMsg;
226         }
227     }
228 }
229