HandlerThread
public class HandlerThread
extends Thread
A Thread
that has a Looper
. The Looper
can then be used to create Handler
s. Just like with a regular Thread
, Thread.start()
must still be called.
Use this class only if you must work with the Handler
API and need a Thread
to do the handling on that is not an existing Looper
thread, such as Looper.getMainLooper()
. Otherwise, prefer Executor
or ExecutorService
, or Kotlin coroutines.
Note that many APIs that required a Handler
in older SDK versions offer a newer alternative that accepts an Executor
instead. Always prefer to use the newer API if available.
Alternatives to HandlerThread
Executor
s offer more flexibility with regards to threading. Work submitted to an Executor
can be set to run on another thread, on one of several threads from a static or dynamic pool, or on the caller's thread, depending on your needs.
{link @link java.util.concurrent.Executor} offers a simpler API that is easier to use compared to Handler
. {link @link java.util.concurrent.ExecutorService} offers the richer Future
API, which you can use to monitor task status, cancel tasks, propagate exceptions, and chain multiple pending tasks.
{link @link java.util.concurrent.Executors} is a factory for various Executor
s that meet common concurrency needs. These Executor
s use work queues that offer better concurrency and reduced contention than HandlerThread
.
On Kotlin, coroutines may be used to handle concurrency.
Apps that use HandlerThread
may encounter the following performance issues:
- Excessive thread creation: A
HandlerThread
is a Thread
. Every system thread costs some resident memory, whether it is working or if it's idle. If your app has a large number of HandlerThread
s each dedicated to a single type of task, rather than for instance a ThreadPoolExecutor
that can grow and shrink in size according to demand, then the additional idle HandlerThread
s will be wasting memory. - Lock contention:
HandlerThread
uses a Looper
which in turn uses a MessageQueue
. MessageQueue
uses a single lock to synchronize access to its underlying queue. Any threads attempting to enqueue messages at the same time, and the HandlerThread
itself when attempting to dequeue the next message to handle, will block each other. - Priority inversion: A high-priority
HandlerThread
can become blocked by a lower-priority thread, for instance if the former is trying to enqueue a message while the latter is trying to dequeue the next message to handle, or vice versa.
The best way to avoid these issues is to use
Executor
s or
Kotlin coroutines instead of
HandlerThread
.
Summary
Public methods |
Looper | getLooper() This method returns the Looper associated with this thread. |
int | getThreadId() Returns the identifier of this thread. |
boolean | quit() Quits the handler thread's looper. |
boolean | quitSafely() Quits the handler thread's looper safely. |
void | run() If this thread was constructed using a separate Runnable run object, then that Runnable object's run method is called; otherwise, this method does nothing and returns. |
Protected methods |
void | onLooperPrepared() Call back method that can be explicitly overridden if needed to execute some setup before Looper loops. |
Inherited methods |
From class java.lang.Thread static int | activeCount() Returns an estimate of the number of active threads in the current thread's thread group and its subgroups. | final void | checkAccess() This method was deprecated in API level 36. This method is only useful in conjunction with the Security Manager, which is deprecated and subject to removal in a future release. Consequently, this method is also deprecated and subject to removal. There is no replacement for the Security Manager or this method. | Object | clone() Throws CloneNotSupportedException as a Thread can not be meaningfully cloned. | static Thread | currentThread() Returns a reference to the currently executing thread object. | static void | dumpStack() Prints a stack trace of the current thread to the standard error stream. | static int | enumerate(Thread[] tarray) Copies into the specified array every active thread in the current thread's thread group and its subgroups. | static Map<Thread, StackTraceElement[]> | getAllStackTraces() Returns a map of stack traces for all live threads. | ClassLoader | getContextClassLoader() Returns the context ClassLoader for this thread. | static Thread.UncaughtExceptionHandler | getDefaultUncaughtExceptionHandler() Returns the default handler invoked when a thread abruptly terminates due to an uncaught exception. | long | getId() This method was deprecated in API level 36. This method is not final and may be overridden to return a value that is not the thread ID. Use threadId() instead. | final String | getName() Returns this thread's name. | final int | getPriority() Returns this thread's priority. | StackTraceElement[] | getStackTrace() Returns an array of stack trace elements representing the stack dump of this thread. | Thread.State | getState() Returns the state of this thread. | final ThreadGroup | getThreadGroup() Returns the thread group to which this thread belongs. | Thread.UncaughtExceptionHandler | getUncaughtExceptionHandler() Returns the handler invoked when this thread abruptly terminates due to an uncaught exception. | static boolean | holdsLock(Object obj) Returns true if and only if the current thread holds the monitor lock on the specified object. | void | interrupt() Interrupts this thread. | static boolean | interrupted() Tests whether the current thread has been interrupted. | final boolean | isAlive() Tests if this thread is alive. | final boolean | isDaemon() Tests if this thread is a daemon thread. | boolean | isInterrupted() Tests whether this thread has been interrupted. | final boolean | isVirtual() Returns true if this thread is a virtual thread. | final void | join() Waits for this thread to die. | final void | join(long millis) Waits at most millis milliseconds for this thread to die. | final void | join(long millis, int nanos) Waits at most millis milliseconds plus nanos nanoseconds for this thread to die. | static void | onSpinWait() Indicates that the caller is momentarily unable to progress, until the occurrence of one or more actions on the part of other activities. | void | run() If this thread was constructed using a separate Runnable run object, then that Runnable object's run method is called; otherwise, this method does nothing and returns. | void | setContextClassLoader(ClassLoader cl) Sets the context ClassLoader for this Thread. | final void | setDaemon(boolean on) Marks this thread as either a daemon thread or a user thread. | static void | setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh) Set the default handler invoked when a thread abruptly terminates due to an uncaught exception, and no other handler has been defined for that thread. | final void | setName(String name) Changes the name of this thread to be equal to the argument name . | final void | setPriority(int newPriority) Changes the priority of this thread. | void | setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh) Set the handler invoked when this thread abruptly terminates due to an uncaught exception. | static void | sleep(long millis, int nanos) Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds plus the specified number of nanoseconds, subject to the precision and accuracy of system timers and schedulers. | static void | sleep(long millis) Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers. | void | start() Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread. | final void | stop() This method was deprecated in API level 15. This method was originally designed to force a thread to stop and throw a ThreadDeath as an exception. It was inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack). If any of the objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to other threads, potentially resulting in arbitrary behavior. Many uses of stop should be replaced by code that simply modifies some variable to indicate that the target thread should stop running. The target thread should check this variable regularly, and return from its run method in an orderly fashion if the variable indicates that it is to stop running. If the target thread waits for long periods (on a condition variable, for example), the interrupt method should be used to interrupt the wait. For more information, see Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?. | final long | threadId() Returns the identifier of this Thread. | String | toString() Returns a string representation of this thread, including the thread's name, priority, and thread group. | static void | yield() A hint to the scheduler that the current thread is willing to yield its current use of a processor. | |
From class java.lang.Object Object | clone() Creates and returns a copy of this object. | boolean | equals(Object obj) Indicates whether some other object is "equal to" this one. | void | finalize() Called by the garbage collector on an object when garbage collection determines that there are no more references to the object. | final Class<?> | getClass() Returns the runtime class of this Object . | int | hashCode() Returns a hash code value for the object. | final void | notify() Wakes up a single thread that is waiting on this object's monitor. | final void | notifyAll() Wakes up all threads that are waiting on this object's monitor. | String | toString() Returns a string representation of the object. | final void | wait(long timeoutMillis, int nanos) Causes the current thread to wait until it is awakened, typically by being notified or interrupted, or until a certain amount of real time has elapsed. | final void | wait(long timeoutMillis) Causes the current thread to wait until it is awakened, typically by being notified or interrupted, or until a certain amount of real time has elapsed. | final void | wait() Causes the current thread to wait until it is awakened, typically by being notified or interrupted. | |
From interface java.lang.Runnable abstract void | run() When an object implementing interface Runnable is used to create a thread, starting the thread causes the object's run method to be called in that separately executing thread. | |
Public constructors
HandlerThread
public HandlerThread (String name)
HandlerThread
public HandlerThread (String name, int priority)
Constructs a HandlerThread.
Parameters |
priority | int : The priority to run the thread at. The value supplied must be from Process and not from java.lang.Thread. |
Public methods
getLooper
public Looper getLooper ()
This method returns the Looper associated with this thread. If this thread not been started or for any reason isAlive() returns false, this method will return null. If this thread has been started, this method will block until the looper has been initialized.
getThreadId
public int getThreadId ()
Returns the identifier of this thread. See Process.myTid().
quit
public boolean quit ()
Quits the handler thread's looper.
Causes the handler thread's looper to terminate without processing any more messages in the message queue.
Any attempt to post messages to the queue after the looper is asked to quit will fail. For example, the Handler.sendMessage(Message)
method will return false.
If quit()
or quitSafely()
is called multiple times, the first call will have an effect and the subsequent calls will be no-ops.
Using this method may be unsafe because some messages may not be delivered before the looper terminates. Consider using quitSafely()
instead to ensure that all pending work is completed in an orderly manner.
Returns |
boolean | True if the looper looper has been asked to quit or false if the thread had not yet started running. |
quitSafely
public boolean quitSafely ()
Quits the handler thread's looper safely.
Causes the handler thread's looper to terminate as soon as all remaining messages in the message queue that are already due to be delivered have been handled. Pending delayed messages with due times in the future will not be delivered.
Any attempt to post messages to the queue after the looper is asked to quit will fail. For example, the Handler.sendMessage(Message)
method will return false.
If the thread has not been started or has finished (that is if getLooper()
returns null), then false is returned. Otherwise the looper is asked to quit and true is returned.
If quit()
or quitSafely()
is called multiple times, the first call will have an effect and the subsequent calls will be no-ops.
Returns |
boolean | True if the looper looper has been asked to quit or false if the thread had not yet started running. |
run
public void run ()
If this thread was constructed using a separate Runnable
run object, then that Runnable
object's run
method is called; otherwise, this method does nothing and returns.
Subclasses of Thread
should override this method.
Protected methods
onLooperPrepared
protected void onLooperPrepared ()
Call back method that can be explicitly overridden if needed to execute some setup before Looper loops.