595 lines
22 KiB
Java
595 lines
22 KiB
Java
/*
|
|
* Copyright (C) 2006 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.os;
|
|
|
|
import android.util.Log;
|
|
import android.util.Printer;
|
|
|
|
import java.lang.reflect.Modifier;
|
|
|
|
/**
|
|
* A Handler allows you to send and process {@link Message} and Runnable
|
|
* objects associated with a thread's {@link MessageQueue}. Each Handler
|
|
* instance is associated with a single thread and that thread's message
|
|
* queue. When you create a new Handler, it is bound to the thread /
|
|
* message queue of the thread that is creating it -- from that point on,
|
|
* it will deliver messages and runnables to that message queue and execute
|
|
* them as they come out of the message queue.
|
|
*
|
|
* <p>There are two main uses for a Handler: (1) to schedule messages and
|
|
* runnables to be executed as some point in the future; and (2) to enqueue
|
|
* an action to be performed on a different thread than your own.
|
|
*
|
|
* <p>Scheduling messages is accomplished with the
|
|
* {@link #post}, {@link #postAtTime(Runnable, long)},
|
|
* {@link #postDelayed}, {@link #sendEmptyMessage},
|
|
* {@link #sendMessage}, {@link #sendMessageAtTime}, and
|
|
* {@link #sendMessageDelayed} methods. The <em>post</em> versions allow
|
|
* you to enqueue Runnable objects to be called by the message queue when
|
|
* they are received; the <em>sendMessage</em> versions allow you to enqueue
|
|
* a {@link Message} object containing a bundle of data that will be
|
|
* processed by the Handler's {@link #handleMessage} method (requiring that
|
|
* you implement a subclass of Handler).
|
|
*
|
|
* <p>When posting or sending to a Handler, you can either
|
|
* allow the item to be processed as soon as the message queue is ready
|
|
* to do so, or specify a delay before it gets processed or absolute time for
|
|
* it to be processed. The latter two allow you to implement timeouts,
|
|
* ticks, and other timing-based behavior.
|
|
*
|
|
* <p>When a
|
|
* process is created for your application, its main thread is dedicated to
|
|
* running a message queue that takes care of managing the top-level
|
|
* application objects (activities, broadcast receivers, etc) and any windows
|
|
* they create. You can create your own threads, and communicate back with
|
|
* the main application thread through a Handler. This is done by calling
|
|
* the same <em>post</em> or <em>sendMessage</em> methods as before, but from
|
|
* your new thread. The given Runnable or Message will than be scheduled
|
|
* in the Handler's message queue and processed when appropriate.
|
|
*/
|
|
public class Handler {
|
|
/*
|
|
* Set this flag to true to detect anonymous, local or member classes
|
|
* that extend this Handler class and that are not static. These kind
|
|
* of classes can potentially create leaks.
|
|
*/
|
|
private static final boolean FIND_POTENTIAL_LEAKS = false;
|
|
private static final String TAG = "Handler";
|
|
|
|
/**
|
|
* Callback interface you can use when instantiating a Handler to avoid
|
|
* having to implement your own subclass of Handler.
|
|
*/
|
|
public interface Callback {
|
|
public boolean handleMessage(Message msg);
|
|
}
|
|
|
|
/**
|
|
* Subclasses must implement this to receive messages.
|
|
*/
|
|
public void handleMessage(Message msg) {
|
|
}
|
|
|
|
/**
|
|
* Handle system messages here.
|
|
*/
|
|
public void dispatchMessage(Message msg) {
|
|
if (msg.callback != null) {
|
|
handleCallback(msg);
|
|
} else {
|
|
if (mCallback != null) {
|
|
if (mCallback.handleMessage(msg)) {
|
|
return;
|
|
}
|
|
}
|
|
handleMessage(msg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Default constructor associates this handler with the queue for the
|
|
* current thread.
|
|
*
|
|
* If there isn't one, this handler won't be able to receive messages.
|
|
*/
|
|
public Handler() {
|
|
if (FIND_POTENTIAL_LEAKS) {
|
|
final Class<? extends Handler> klass = getClass();
|
|
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
|
|
(klass.getModifiers() & Modifier.STATIC) == 0) {
|
|
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
|
|
klass.getCanonicalName());
|
|
}
|
|
}
|
|
|
|
mLooper = Looper.myLooper();
|
|
if (mLooper == null) {
|
|
throw new RuntimeException(
|
|
"Can't create handler inside thread that has not called Looper.prepare()");
|
|
}
|
|
mQueue = mLooper.mQueue;
|
|
mCallback = null;
|
|
}
|
|
|
|
/**
|
|
* Constructor associates this handler with the queue for the
|
|
* current thread and takes a callback interface in which you can handle
|
|
* messages.
|
|
*/
|
|
public Handler(Callback callback) {
|
|
if (FIND_POTENTIAL_LEAKS) {
|
|
final Class<? extends Handler> klass = getClass();
|
|
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
|
|
(klass.getModifiers() & Modifier.STATIC) == 0) {
|
|
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
|
|
klass.getCanonicalName());
|
|
}
|
|
}
|
|
|
|
mLooper = Looper.myLooper();
|
|
if (mLooper == null) {
|
|
throw new RuntimeException(
|
|
"Can't create handler inside thread that has not called Looper.prepare()");
|
|
}
|
|
mQueue = mLooper.mQueue;
|
|
mCallback = callback;
|
|
}
|
|
|
|
/**
|
|
* Use the provided queue instead of the default one.
|
|
*/
|
|
public Handler(Looper looper) {
|
|
mLooper = looper;
|
|
mQueue = looper.mQueue;
|
|
mCallback = null;
|
|
}
|
|
|
|
/**
|
|
* Use the provided queue instead of the default one and take a callback
|
|
* interface in which to handle messages.
|
|
*/
|
|
public Handler(Looper looper, Callback callback) {
|
|
mLooper = looper;
|
|
mQueue = looper.mQueue;
|
|
mCallback = callback;
|
|
}
|
|
|
|
/**
|
|
* Returns a new {@link android.os.Message Message} from the global message pool. More efficient than
|
|
* creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
|
|
* If you don't want that facility, just call Message.obtain() instead.
|
|
*/
|
|
public final Message obtainMessage()
|
|
{
|
|
return Message.obtain(this);
|
|
}
|
|
|
|
/**
|
|
* Same as {@link #obtainMessage()}, except that it also sets the what member of the returned Message.
|
|
*
|
|
* @param what Value to assign to the returned Message.what field.
|
|
* @return A Message from the global message pool.
|
|
*/
|
|
public final Message obtainMessage(int what)
|
|
{
|
|
return Message.obtain(this, what);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Same as {@link #obtainMessage()}, except that it also sets the what and obj members
|
|
* of the returned Message.
|
|
*
|
|
* @param what Value to assign to the returned Message.what field.
|
|
* @param obj Value to assign to the returned Message.obj field.
|
|
* @return A Message from the global message pool.
|
|
*/
|
|
public final Message obtainMessage(int what, Object obj)
|
|
{
|
|
return Message.obtain(this, what, obj);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Same as {@link #obtainMessage()}, except that it also sets the what, arg1 and arg2 members of the returned
|
|
* Message.
|
|
* @param what Value to assign to the returned Message.what field.
|
|
* @param arg1 Value to assign to the returned Message.arg1 field.
|
|
* @param arg2 Value to assign to the returned Message.arg2 field.
|
|
* @return A Message from the global message pool.
|
|
*/
|
|
public final Message obtainMessage(int what, int arg1, int arg2)
|
|
{
|
|
return Message.obtain(this, what, arg1, arg2);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Same as {@link #obtainMessage()}, except that it also sets the what, obj, arg1,and arg2 values on the
|
|
* returned Message.
|
|
* @param what Value to assign to the returned Message.what field.
|
|
* @param arg1 Value to assign to the returned Message.arg1 field.
|
|
* @param arg2 Value to assign to the returned Message.arg2 field.
|
|
* @param obj Value to assign to the returned Message.obj field.
|
|
* @return A Message from the global message pool.
|
|
*/
|
|
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
|
|
{
|
|
return Message.obtain(this, what, arg1, arg2, obj);
|
|
}
|
|
|
|
/**
|
|
* Causes the Runnable r to be added to the message queue.
|
|
* The runnable will be run on the thread to which this handler is
|
|
* attached.
|
|
*
|
|
* @param r The Runnable that will be executed.
|
|
*
|
|
* @return Returns true if the Runnable was successfully placed in to the
|
|
* message queue. Returns false on failure, usually because the
|
|
* looper processing the message queue is exiting.
|
|
*/
|
|
public final boolean post(Runnable r)
|
|
{
|
|
return sendMessageDelayed(getPostMessage(r), 0);
|
|
}
|
|
|
|
/**
|
|
* Causes the Runnable r to be added to the message queue, to be run
|
|
* at a specific time given by <var>uptimeMillis</var>.
|
|
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
|
|
* The runnable will be run on the thread to which this handler is attached.
|
|
*
|
|
* @param r The Runnable that will be executed.
|
|
* @param uptimeMillis The absolute time at which the callback should run,
|
|
* using the {@link android.os.SystemClock#uptimeMillis} time-base.
|
|
*
|
|
* @return Returns true if the Runnable was successfully placed in to the
|
|
* message queue. Returns false on failure, usually because the
|
|
* looper processing the message queue is exiting. Note that a
|
|
* result of true does not mean the Runnable will be processed -- if
|
|
* the looper is quit before the delivery time of the message
|
|
* occurs then the message will be dropped.
|
|
*/
|
|
public final boolean postAtTime(Runnable r, long uptimeMillis)
|
|
{
|
|
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
|
|
}
|
|
|
|
/**
|
|
* Causes the Runnable r to be added to the message queue, to be run
|
|
* at a specific time given by <var>uptimeMillis</var>.
|
|
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
|
|
* The runnable will be run on the thread to which this handler is attached.
|
|
*
|
|
* @param r The Runnable that will be executed.
|
|
* @param uptimeMillis The absolute time at which the callback should run,
|
|
* using the {@link android.os.SystemClock#uptimeMillis} time-base.
|
|
*
|
|
* @return Returns true if the Runnable was successfully placed in to the
|
|
* message queue. Returns false on failure, usually because the
|
|
* looper processing the message queue is exiting. Note that a
|
|
* result of true does not mean the Runnable will be processed -- if
|
|
* the looper is quit before the delivery time of the message
|
|
* occurs then the message will be dropped.
|
|
*
|
|
* @see android.os.SystemClock#uptimeMillis
|
|
*/
|
|
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
|
|
{
|
|
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
|
|
}
|
|
|
|
/**
|
|
* Causes the Runnable r to be added to the message queue, to be run
|
|
* after the specified amount of time elapses.
|
|
* The runnable will be run on the thread to which this handler
|
|
* is attached.
|
|
*
|
|
* @param r The Runnable that will be executed.
|
|
* @param delayMillis The delay (in milliseconds) until the Runnable
|
|
* will be executed.
|
|
*
|
|
* @return Returns true if the Runnable was successfully placed in to the
|
|
* message queue. Returns false on failure, usually because the
|
|
* looper processing the message queue is exiting. Note that a
|
|
* result of true does not mean the Runnable will be processed --
|
|
* if the looper is quit before the delivery time of the message
|
|
* occurs then the message will be dropped.
|
|
*/
|
|
public final boolean postDelayed(Runnable r, long delayMillis)
|
|
{
|
|
return sendMessageDelayed(getPostMessage(r), delayMillis);
|
|
}
|
|
|
|
/**
|
|
* Posts a message to an object that implements Runnable.
|
|
* Causes the Runnable r to executed on the next iteration through the
|
|
* message queue. The runnable will be run on the thread to which this
|
|
* handler is attached.
|
|
* <b>This method is only for use in very special circumstances -- it
|
|
* can easily starve the message queue, cause ordering problems, or have
|
|
* other unexpected side-effects.</b>
|
|
*
|
|
* @param r The Runnable that will be executed.
|
|
*
|
|
* @return Returns true if the message was successfully placed in to the
|
|
* message queue. Returns false on failure, usually because the
|
|
* looper processing the message queue is exiting.
|
|
*/
|
|
public final boolean postAtFrontOfQueue(Runnable r)
|
|
{
|
|
return sendMessageAtFrontOfQueue(getPostMessage(r));
|
|
}
|
|
|
|
/**
|
|
* Remove any pending posts of Runnable r that are in the message queue.
|
|
*/
|
|
public final void removeCallbacks(Runnable r)
|
|
{
|
|
mQueue.removeMessages(this, r, null);
|
|
}
|
|
|
|
/**
|
|
* Remove any pending posts of Runnable <var>r</var> with Object
|
|
* <var>token</var> that are in the message queue.
|
|
*/
|
|
public final void removeCallbacks(Runnable r, Object token)
|
|
{
|
|
mQueue.removeMessages(this, r, token);
|
|
}
|
|
|
|
/**
|
|
* Pushes a message onto the end of the message queue after all pending messages
|
|
* before the current time. It will be received in {@link #handleMessage},
|
|
* in the thread attached to this handler.
|
|
*
|
|
* @return Returns true if the message was successfully placed in to the
|
|
* message queue. Returns false on failure, usually because the
|
|
* looper processing the message queue is exiting.
|
|
*/
|
|
public final boolean sendMessage(Message msg)
|
|
{
|
|
return sendMessageDelayed(msg, 0);
|
|
}
|
|
|
|
/**
|
|
* Sends a Message containing only the what value.
|
|
*
|
|
* @return Returns true if the message was successfully placed in to the
|
|
* message queue. Returns false on failure, usually because the
|
|
* looper processing the message queue is exiting.
|
|
*/
|
|
public final boolean sendEmptyMessage(int what)
|
|
{
|
|
return sendEmptyMessageDelayed(what, 0);
|
|
}
|
|
|
|
/**
|
|
* Sends a Message containing only the what value, to be delivered
|
|
* after the specified amount of time elapses.
|
|
* @see #sendMessageDelayed(android.os.Message, long)
|
|
*
|
|
* @return Returns true if the message was successfully placed in to the
|
|
* message queue. Returns false on failure, usually because the
|
|
* looper processing the message queue is exiting.
|
|
*/
|
|
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
|
|
Message msg = Message.obtain();
|
|
msg.what = what;
|
|
return sendMessageDelayed(msg, delayMillis);
|
|
}
|
|
|
|
/**
|
|
* Sends a Message containing only the what value, to be delivered
|
|
* at a specific time.
|
|
* @see #sendMessageAtTime(android.os.Message, long)
|
|
*
|
|
* @return Returns true if the message was successfully placed in to the
|
|
* message queue. Returns false on failure, usually because the
|
|
* looper processing the message queue is exiting.
|
|
*/
|
|
|
|
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
|
|
Message msg = Message.obtain();
|
|
msg.what = what;
|
|
return sendMessageAtTime(msg, uptimeMillis);
|
|
}
|
|
|
|
/**
|
|
* Enqueue a message into the message queue after all pending messages
|
|
* before (current time + delayMillis). You will receive it in
|
|
* {@link #handleMessage}, in the thread attached to this handler.
|
|
*
|
|
* @return Returns true if the message was successfully placed in to the
|
|
* message queue. Returns false on failure, usually because the
|
|
* looper processing the message queue is exiting. Note that a
|
|
* result of true does not mean the message will be processed -- if
|
|
* the looper is quit before the delivery time of the message
|
|
* occurs then the message will be dropped.
|
|
*/
|
|
public final boolean sendMessageDelayed(Message msg, long delayMillis)
|
|
{
|
|
if (delayMillis < 0) {
|
|
delayMillis = 0;
|
|
}
|
|
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
|
|
}
|
|
|
|
/**
|
|
* Enqueue a message into the message queue after all pending messages
|
|
* before the absolute time (in milliseconds) <var>uptimeMillis</var>.
|
|
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
|
|
* You will receive it in {@link #handleMessage}, in the thread attached
|
|
* to this handler.
|
|
*
|
|
* @param uptimeMillis The absolute time at which the message should be
|
|
* delivered, using the
|
|
* {@link android.os.SystemClock#uptimeMillis} time-base.
|
|
*
|
|
* @return Returns true if the message was successfully placed in to the
|
|
* message queue. Returns false on failure, usually because the
|
|
* looper processing the message queue is exiting. Note that a
|
|
* result of true does not mean the message will be processed -- if
|
|
* the looper is quit before the delivery time of the message
|
|
* occurs then the message will be dropped.
|
|
*/
|
|
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
|
|
{
|
|
boolean sent = false;
|
|
MessageQueue queue = mQueue;
|
|
if (queue != null) {
|
|
msg.target = this;
|
|
sent = queue.enqueueMessage(msg, uptimeMillis);
|
|
}
|
|
else {
|
|
RuntimeException e = new RuntimeException(
|
|
this + " sendMessageAtTime() called with no mQueue");
|
|
Log.w("Looper", e.getMessage(), e);
|
|
}
|
|
return sent;
|
|
}
|
|
|
|
/**
|
|
* Enqueue a message at the front of the message queue, to be processed on
|
|
* the next iteration of the message loop. You will receive it in
|
|
* {@link #handleMessage}, in the thread attached to this handler.
|
|
* <b>This method is only for use in very special circumstances -- it
|
|
* can easily starve the message queue, cause ordering problems, or have
|
|
* other unexpected side-effects.</b>
|
|
*
|
|
* @return Returns true if the message was successfully placed in to the
|
|
* message queue. Returns false on failure, usually because the
|
|
* looper processing the message queue is exiting.
|
|
*/
|
|
public final boolean sendMessageAtFrontOfQueue(Message msg)
|
|
{
|
|
boolean sent = false;
|
|
MessageQueue queue = mQueue;
|
|
if (queue != null) {
|
|
msg.target = this;
|
|
sent = queue.enqueueMessage(msg, 0);
|
|
}
|
|
else {
|
|
RuntimeException e = new RuntimeException(
|
|
this + " sendMessageAtTime() called with no mQueue");
|
|
Log.w("Looper", e.getMessage(), e);
|
|
}
|
|
return sent;
|
|
}
|
|
|
|
/**
|
|
* Remove any pending posts of messages with code 'what' that are in the
|
|
* message queue.
|
|
*/
|
|
public final void removeMessages(int what) {
|
|
mQueue.removeMessages(this, what, null, true);
|
|
}
|
|
|
|
/**
|
|
* Remove any pending posts of messages with code 'what' and whose obj is
|
|
* 'object' that are in the message queue.
|
|
*/
|
|
public final void removeMessages(int what, Object object) {
|
|
mQueue.removeMessages(this, what, object, true);
|
|
}
|
|
|
|
/**
|
|
* Remove any pending posts of callbacks and sent messages whose
|
|
* <var>obj</var> is <var>token</var>.
|
|
*/
|
|
public final void removeCallbacksAndMessages(Object token) {
|
|
mQueue.removeCallbacksAndMessages(this, token);
|
|
}
|
|
|
|
/**
|
|
* Check if there are any pending posts of messages with code 'what' in
|
|
* the message queue.
|
|
*/
|
|
public final boolean hasMessages(int what) {
|
|
return mQueue.removeMessages(this, what, null, false);
|
|
}
|
|
|
|
/**
|
|
* Check if there are any pending posts of messages with code 'what' and
|
|
* whose obj is 'object' in the message queue.
|
|
*/
|
|
public final boolean hasMessages(int what, Object object) {
|
|
return mQueue.removeMessages(this, what, object, false);
|
|
}
|
|
|
|
// if we can get rid of this method, the handler need not remember its loop
|
|
// we could instead export a getMessageQueue() method...
|
|
public final Looper getLooper() {
|
|
return mLooper;
|
|
}
|
|
|
|
public final void dump(Printer pw, String prefix) {
|
|
pw.println(prefix + this + " @ " + SystemClock.uptimeMillis());
|
|
if (mLooper == null) {
|
|
pw.println(prefix + "looper uninitialized");
|
|
} else {
|
|
mLooper.dump(pw, prefix + " ");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "Handler{"
|
|
+ Integer.toHexString(System.identityHashCode(this))
|
|
+ "}";
|
|
}
|
|
|
|
final IMessenger getIMessenger() {
|
|
synchronized (mQueue) {
|
|
if (mMessenger != null) {
|
|
return mMessenger;
|
|
}
|
|
mMessenger = new MessengerImpl();
|
|
return mMessenger;
|
|
}
|
|
}
|
|
|
|
private final class MessengerImpl extends IMessenger.Stub {
|
|
public void send(Message msg) {
|
|
Handler.this.sendMessage(msg);
|
|
}
|
|
}
|
|
|
|
private final Message getPostMessage(Runnable r) {
|
|
Message m = Message.obtain();
|
|
m.callback = r;
|
|
return m;
|
|
}
|
|
|
|
private final Message getPostMessage(Runnable r, Object token) {
|
|
Message m = Message.obtain();
|
|
m.obj = token;
|
|
m.callback = r;
|
|
return m;
|
|
}
|
|
|
|
private final void handleCallback(Message message) {
|
|
message.callback.run();
|
|
}
|
|
|
|
final MessageQueue mQueue;
|
|
final Looper mLooper;
|
|
final Callback mCallback;
|
|
IMessenger mMessenger;
|
|
}
|