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         // If the thread has been started, wait until the looper has been created.
83         synchronized (this) {
84             while (isAlive() && mLooper == null) {
85                 try {
86                     wait();
87                 } catch (InterruptedException e) {
88                 }
89             }
90         }
91         return mLooper;
92     }
93 
94     /**
95      * @return a shared {@link Handler} associated with this thread
96      * @hide
97      */
98     @NonNull
getThreadHandler()99     public Handler getThreadHandler() {
100         if (mHandler == null) {
101             mHandler = new Handler(getLooper());
102         }
103         return mHandler;
104     }
105 
106     /**
107      * Quits the handler thread's looper.
108      * <p>
109      * Causes the handler thread's looper to terminate without processing any
110      * more messages in the message queue.
111      * </p><p>
112      * Any attempt to post messages to the queue after the looper is asked to quit will fail.
113      * For example, the {@link Handler#sendMessage(Message)} method will return false.
114      * </p><p class="note">
115      * Using this method may be unsafe because some messages may not be delivered
116      * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
117      * that all pending work is completed in an orderly manner.
118      * </p>
119      *
120      * @return True if the looper looper has been asked to quit or false if the
121      * thread had not yet started running.
122      *
123      * @see #quitSafely
124      */
quit()125     public boolean quit() {
126         Looper looper = getLooper();
127         if (looper != null) {
128             looper.quit();
129             return true;
130         }
131         return false;
132     }
133 
134     /**
135      * Quits the handler thread's looper safely.
136      * <p>
137      * Causes the handler thread's looper to terminate as soon as all remaining messages
138      * in the message queue that are already due to be delivered have been handled.
139      * Pending delayed messages with due times in the future will not be delivered.
140      * </p><p>
141      * Any attempt to post messages to the queue after the looper is asked to quit will fail.
142      * For example, the {@link Handler#sendMessage(Message)} method will return false.
143      * </p><p>
144      * If the thread has not been started or has finished (that is if
145      * {@link #getLooper} returns null), then false is returned.
146      * Otherwise the looper is asked to quit and true is returned.
147      * </p>
148      *
149      * @return True if the looper looper has been asked to quit or false if the
150      * thread had not yet started running.
151      */
quitSafely()152     public boolean quitSafely() {
153         Looper looper = getLooper();
154         if (looper != null) {
155             looper.quitSafely();
156             return true;
157         }
158         return false;
159     }
160 
161     /**
162      * Returns the identifier of this thread. See Process.myTid().
163      */
getThreadId()164     public int getThreadId() {
165         return mTid;
166     }
167 }
168