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.annotation.NonNull;
20 import android.annotation.Nullable;
21 
22 /**
23  * A {@link Thread} that has a {@link Looper}.
24  * The {@link Looper} can then be used to create {@link Handler}s.
25  * <p>
26  * Note that just like with a regular {@link Thread}, {@link #start()} must still be called.
27  */
28 public class HandlerThread extends Thread {
29     int mPriority;
30     int mTid = -1;
31     Looper mLooper;
32     private @Nullable Handler mHandler;
33 
HandlerThread(String name)34     public HandlerThread(String name) {
35         super(name);
36         mPriority = Process.THREAD_PRIORITY_DEFAULT;
37     }
38 
39     /**
40      * Constructs a HandlerThread.
41      * @param name
42      * @param priority The priority to run the thread at. The value supplied must be from
43      * {@link android.os.Process} and not from java.lang.Thread.
44      */
HandlerThread(String name, int priority)45     public HandlerThread(String name, int priority) {
46         super(name);
47         mPriority = priority;
48     }
49 
50     /**
51      * Call back method that can be explicitly overridden if needed to execute some
52      * setup before Looper loops.
53      */
onLooperPrepared()54     protected void onLooperPrepared() {
55     }
56 
57     @Override
run()58     public void run() {
59         mTid = Process.myTid();
60         Looper.prepare();
61         synchronized (this) {
62             mLooper = Looper.myLooper();
63             notifyAll();
64         }
65         Process.setThreadPriority(mPriority);
66         onLooperPrepared();
67         Looper.loop();
68         mTid = -1;
69     }
70 
71     /**
72      * This method returns the Looper associated with this thread. If this thread not been started
73      * or for any reason isAlive() returns false, this method will return null. If this thread
74      * has been started, this method will block until the looper has been initialized.
75      * @return The looper.
76      */
getLooper()77     public Looper getLooper() {
78         if (!isAlive()) {
79             return null;
80         }
81 
82         boolean wasInterrupted = false;
83 
84         // If the thread has been started, wait until the looper has been created.
85         synchronized (this) {
86             while (isAlive() && mLooper == null) {
87                 try {
88                     wait();
89                 } catch (InterruptedException e) {
90                     wasInterrupted = true;
91                 }
92             }
93         }
94 
95         /*
96          * We may need to restore the thread's interrupted flag, because it may
97          * have been cleared above since we eat InterruptedExceptions
98          */
99         if (wasInterrupted) {
100             Thread.currentThread().interrupt();
101         }
102 
103         return mLooper;
104     }
105 
106     /**
107      * @return a shared {@link Handler} associated with this thread
108      * @hide
109      */
110     @NonNull
getThreadHandler()111     public Handler getThreadHandler() {
112         if (mHandler == null) {
113             mHandler = new Handler(getLooper());
114         }
115         return mHandler;
116     }
117 
118     /**
119      * Quits the handler thread's looper.
120      * <p>
121      * Causes the handler thread's looper to terminate without processing any
122      * more messages in the message queue.
123      * </p><p>
124      * Any attempt to post messages to the queue after the looper is asked to quit will fail.
125      * For example, the {@link Handler#sendMessage(Message)} method will return false.
126      * </p><p class="note">
127      * Using this method may be unsafe because some messages may not be delivered
128      * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
129      * that all pending work is completed in an orderly manner.
130      * </p>
131      *
132      * @return True if the looper looper has been asked to quit or false if the
133      * thread had not yet started running.
134      *
135      * @see #quitSafely
136      */
quit()137     public boolean quit() {
138         Looper looper = getLooper();
139         if (looper != null) {
140             looper.quit();
141             return true;
142         }
143         return false;
144     }
145 
146     /**
147      * Quits the handler thread's looper safely.
148      * <p>
149      * Causes the handler thread's looper to terminate as soon as all remaining messages
150      * in the message queue that are already due to be delivered have been handled.
151      * Pending delayed messages with due times in the future will not be delivered.
152      * </p><p>
153      * Any attempt to post messages to the queue after the looper is asked to quit will fail.
154      * For example, the {@link Handler#sendMessage(Message)} method will return false.
155      * </p><p>
156      * If the thread has not been started or has finished (that is if
157      * {@link #getLooper} returns null), then false is returned.
158      * Otherwise the looper is asked to quit and true is returned.
159      * </p>
160      *
161      * @return True if the looper looper has been asked to quit or false if the
162      * thread had not yet started running.
163      */
quitSafely()164     public boolean quitSafely() {
165         Looper looper = getLooper();
166         if (looper != null) {
167             looper.quitSafely();
168             return true;
169         }
170         return false;
171     }
172 
173     /**
174      * Returns the identifier of this thread. See Process.myTid().
175      */
getThreadId()176     public int getThreadId() {
177         return mTid;
178     }
179 }
180