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