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