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