总结
Handler类的主要作用是发送一个Message信息到消息队列,根据持有的Looper决定把Message发送到那个线程的消息队列,也可以延时发送,在Looper#loop方法中
msg.target.dispatchMessage(msg)
开始分发结果。如果不在需要发送Message消息,先查看一下消息队列中是否有此消息。根据条件removeMessages。
代码
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
tv_handler_test_result.setText((String) msg.obj);
break;
}
}
};
private TextView tv_handler_test_result;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_test);
tv_handler_test_result = (TextView) findViewById(R.id.tv_handler_test_result);
Button btn_handler_test_send = (Button) findViewById(R.id.btn_handler_test_send);
btn_handler_test_send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message obtain = Message.obtain();
obtain.obj = "来吧兄弟!";
obtain.what = 0;
handler.sendMessage(obtain);
super.run();
}
}.start();
}
});
}
简单到令人发指的代码。点击button按钮发送,子线程延时5秒发送信息。在handler接受到信息,回显到textview中。
handler 如何工作
handler类的描述
/**
* 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.
*
* 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.
*
*
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 post versions allow
* you to enqueue Runnable objects to be called by the message queue when
* they are received; the sendMessage 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).
*
*
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.
*
*
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 post or sendMessage methods as before, but from
* your new thread. The given Runnable or Message will then be scheduled
* in the Handler's message queue and processed when appropriate.
*/
翻译:Handler允许你发送和处理与线程的MessageQueue相关的Message和Runnable对象。
每一个实例都与单个线程和该线程的MessageQueue相关联。
如果创建一个新的Handler,它 绑定到 正在创建他的线程 的线程/messageQueue,在这一刻起,handler将分发Message,或者Runnable,并发送到消息队列Message Queue。
handler有两个主要的作用:
- 在将来的某个时间点去调度Message和Runnable
- 在另一个线程上去执行队列
发送消息是通过下面的一些方法发送的:
post类型
{@link #post}, {@link #postAtTime(Runnable, long)}, {@link #postDelayed}允许发送runnable,接收到message调用在runnable中。
send类型{@link #sendEmptyMessage}, {@link #sendMessage}, {@link #sendMessageAtTime}, and {@link #sendMessageDelayed}
发送的是Messge对象,回调在handlerMessage方法中。
当正在发送Handler时,可以选择立刻发送消息或者指定延时时间在发送消息。
为应用程序创建一个进程时,其主线程将专门运行一个消息队列,负责管理顶级应用程序对象(活动,广播接收器等)及其创建的任何窗口。 也可以创建自己的线程,并通过Handler与主线程进行通信。 这是通过调用与之前相同的 post em>或 sendMessage em>方法来完成的,但是是从新线程调用的。 然后给定的Runnable或Message将在Handler的消息队列中进行调度,并在适当的时候进行处理
默认构造
/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
public Handler() {
this(null, false);
}
翻译:默认的构造,handler和当前的线程Looper相关联。
如果这个线程没有looper,handler不想接受你的线程,并向你抛出个异常。
CallBack构造
/**
* Constructor associates this handler with the {@link Looper} for the
* current thread and takes a callback interface in which you can handle
* messages.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*
* @param callback The callback interface in which to handle messages, or null.
*/
public Handler(Callback callback) {
this(callback, false);
}
callback自定义回调,可以自己处理message
Looper构造
/**
* Use the provided {@link Looper} instead of the default one.
*
* @param looper The looper, must not be null.
*/
public Handler(Looper looper) {
this(looper, null, false);
}
使用自己定义的looper 而不是默认的looper,looper不能为空
Looper CallBack构造
/**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages.
*
* @param looper The looper, must not be null.
* @param callback The callback interface in which to handle messages, or null.
*/
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
boolean async 构造
/**
* Use the {@link Looper} for the current thread
* and set whether the handler should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(boolean async) {
this(null, async);
}
使用当前线程的looper,并设置handler是否应该是异步的。
默认是同步的,除非使用这个构造来创建一个严格的异步。
异步消息表示不需要遵守同步消息的全局排序的中断或事件。 异步消息不受由{@link MessageQueue#enqueueSyncBarrier(long)}引入的同步障碍的限制
CallBack回调接口
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
public interface Callback {
public boolean handleMessage(Message msg);
}
结果回调接口
返回:ture 表示不需要继续处理了
真正调用的构造
使用上面的哪些构造都是使用了一些默认的参数。到这里才是开始真正的开始。
这里主要有两个构造主要看参数。
/**
* Use the {@link Looper} for the current thread with the specified callback interface
* and set whether the handler should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(Callback callback, boolean async) {
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;
mAsynchronous = async;
}
这个构造是隐藏的,当loop==null就会抛出异常。
myLooper()方法 会返回一个与当前线程相关联的looper对象,如果线程没有和looper相关联 就会返回null.
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
如果不调用prepare()方法 ,sThreadLocal.get()会返回null.
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal sThreadLocal = new ThreadLocal();
FIND_POTENTIAL_LEAKS 默认为false,将此标志设置为true以检测,局部或成员类。 这些类可能会造成泄漏。
/**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages. Also set whether the handler
* should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param looper The looper, must not be null.
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
这个就比较简单了,使用提供的{@link Looper}而不是默认的,并采用一个回调接口来处理消息。 还要设置处理程序是否应该是异步的。
getMessageName
/**
* Returns a string representing the name of the specified message.
* The default implementation will either return the class name of the
* message callback if any, or the hexadecimal representation of the
* message "what" field.
*
* @param message The message whose name is being queried
*/
public String getMessageName(Message message) {
if (message.callback != null) {
return message.callback.getClass().getName();
}
return "0x" + Integer.toHexString(message.what);
}
返回表示指定消息的名称的字符串。默认实现将返回消息回调的类名或消息“what”字段的十六进制表示形式。
/**
* 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);
}
获取Message系列和Message.obtainMessage()效果一样;其实就是一样的。
post系列
- post
/**
* 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);
}
把自定义的runnable 添加到消息队列中。runnable将运行在handler关联的线程上。
- postAtTime延时发送消息
public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
发送延时消息,与上面的差不多,加入延时时间,如果在深度睡眠中,会添加延时时间。
- postDelayed
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
post系列 无非就是调用sendMessageDelayed或者sendMessageAtTime,都是发送延时消息。首先来看看getPostMessage(r)这个方法,下面就是这个方法的实现,首先new出一个Message的实例,然后把runnable赋值到Message的回调中。
也就说明Measage中的Callback其实就是我们自定义的Runnable,所以使用post系列发送消息的,Message都有Callback,而在handler类中,message.callback 其实就是自己定义的runnable
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
在来看sendMessageDelayed方法,也是调用sendMessageAtTime方法,SystemClock.uptimeMillis() + delayMillis。delayMillis延时时间
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
- post系列最终都是调用这个方法 sendMessageAtTime
/**
* Enqueue a message into the message queue after all pending messages
* before the absolute time (in milliseconds) uptimeMillis.
* The time-base is {@link android.os.SystemClock#uptimeMillis}.
* Time spent in deep sleep will add an additional delay to execution.
* 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) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
首先查看mQueue消息队列是否为null,最后执行enqueueMessage方法。这里的延迟时间 你写个5000之类的就错了,需要加上SystemClock.uptimeMillis()。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
把当前的handler赋值给Message的target,具体有什么用,咱现在也不知道,但是要有个印象记住这个target。mAsynchronous是构造的时候是否需要异步。最后执行消息队列中的EnqueueMessage方法。
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
接受两个参数 消息 和 时间,第一步,比较熟悉,刚才那个target看见没,直接已经告诉你了 Message必须得有一个target,具体啥用 现在还不知道。第二部呢从名字上也能分辨 这个message有没有正在使用,如果正在使用呢 那就抛异常吧。同步锁,然后判断是否正在退出中,mQuitting其实表示Looper如果Looper正在关闭中,你不应该在去发送消息了。markInUse表示Message正在处理中。后面比较复杂不懂。一会在看
- isInUse()
/*package*/ static final int FLAG_IN_USE = 1 << 0;
/*package*/ int flags;
/*package*/ boolean isInUse() {
return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
}
- markInUse
/*package*/ void markInUse() {
flags |= FLAG_IN_USE;
}
- sendMessageAtFrontOfQueue 这个方法会把消息方在队列的最前面
/**
* 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.
* 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.
*
* @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) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, 0);
}
把消息放在消息队列的最前面,在消息循环中的下一次处理,这个方法很容易出险问题,比如排序问题和其它未知问题。
removeMessages 系列
/**
* 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);
}
根据what移除所有在消息队列等待发送的消息。
/**
* Remove any pending posts of messages with code 'what' and whose obj is
* 'object' that are in the message queue. If object is null,
* all messages will be removed.
*/
public final void removeMessages(int what, Object object) {
mQueue.removeMessages(this, what, object);
}
跟上一个方法类似,多了一个obj,如果obj为null,则删除所有。
/**
* Remove any pending posts of callbacks and sent messages whose
* obj is token. If token is null,
* all callbacks and messages will be removed.
*/
public final void removeCallbacksAndMessages(Object token) {
mQueue.removeCallbacksAndMessages(this, token);
}
类似,如果token为null,则删除所有message和callback
hasMessages 系列
/**
* Check if there are any pending posts of messages with code 'what' in
* the message queue.
*/
public final boolean hasMessages(int what) {
return mQueue.hasMessages(this, what, null);
}
/**
* 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.hasMessages(this, what, object);
}
/**
* Check if there are any pending posts of messages with callback r in
* the message queue.
*
* @hide
*/
public final boolean hasCallbacks(Runnable r) {
return mQueue.hasMessages(this, r, null);
}
校验消息队列中,是否有要发送的runnable或者message
回调
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);
}
}
dispatchMessage方法在Looper#loop()中被调用,msg就是发送出来的结果,在发送给handleMessage或者handleCallback,这里就看你代码中使用的是哪一种回调了。
其它
/**
* Runs the specified task synchronously.
*
* If the current thread is the same as the handler thread, then the runnable
* runs immediately without being enqueued. Otherwise, posts the runnable
* to the handler and waits for it to complete before returning.
*
* This method is dangerous! Improper use can result in deadlocks.
* Never call this method while any locks are held or use it in a
* possibly re-entrant manner.
*
* This method is occasionally useful in situations where a background thread
* must synchronously await completion of a task that must run on the
* handler's thread. However, this problem is often a symptom of bad design.
* Consider improving the design (if possible) before resorting to this method.
*
* One example of where you might want to use this method is when you just
* set up a Handler thread and need to perform some initialization steps on
* it before continuing execution.
*
* If timeout occurs then this method returns false
but the runnable
* will remain posted on the handler and may already be in progress or
* complete at a later time.
*
* When using this method, be sure to use {@link Looper#quitSafely} when
* quitting the looper. Otherwise {@link #runWithScissors} may hang indefinitely.
* (TODO: We should fix this by making MessageQueue aware of blocking runnables.)
*
*
* @param r The Runnable that will be executed synchronously.
* @param timeout The timeout in milliseconds, or 0 to wait indefinitely.
*
* @return Returns true if the Runnable was successfully executed.
* Returns false on failure, usually because the
* looper processing the message queue is exiting.
*
* @hide This method is prone to abuse and should probably not be in the API.
* If we ever do make it part of the API, we might want to rename it to something
* less funny like runUnsafe().
*/
public final boolean runWithScissors(final Runnable r, long timeout) {
if (r == null) {
throw new IllegalArgumentException("runnable must not be null");
}
if (timeout < 0) {
throw new IllegalArgumentException("timeout must be non-negative");
}
if (Looper.myLooper() == mLooper) {
r.run();
return true;
}
BlockingRunnable br = new BlockingRunnable(r);
return br.postAndWait(this, timeout);
}
翻译:同步运行指定的任务
如果当前线程与处理程序线程相同,则runnable立即运行而不被入队。否则,将runnable发布到处理程序,并在返回之前等待它完成。这种方法很危险!不正确的使用会导致死锁。永远不要在保持锁的时候调用这个方法,或者以可能的方式重新使用它。
在后台线程必须同步等待完成必须在处理程序线程上运行的任务的情况下,此方法偶尔很有用。但是,这个问题往往是设计不好的一个症状。考虑在采用这种方法之前改进设计(如果可能的话)
您只需设置一个Handler线程,并在继续执行之前需要对其执行一些初始化步骤
如果发生超时,则此方法返回
false code>,但runnable将保留在处理程序上,并且可能已在进行或稍后完成。
private static final class BlockingRunnable implements Runnable {
private final Runnable mTask;
private boolean mDone;
public BlockingRunnable(Runnable task) {
mTask = task;
}
@Override
public void run() {
try {
mTask.run();
} finally {
synchronized (this) {
mDone = true;
notifyAll();
}
}
}
public boolean postAndWait(Handler handler, long timeout) {
if (!handler.post(this)) {
return false;
}
synchronized (this) {
if (timeout > 0) {
final long expirationTime = SystemClock.uptimeMillis() + timeout;
while (!mDone) {
long delay = expirationTime - SystemClock.uptimeMillis();
if (delay <= 0) {
return false; // timeout
}
try {
wait(delay);
} catch (InterruptedException ex) {
}
}
} else {
while (!mDone) {
try {
wait();
} catch (InterruptedException ex) {
}
}
}
}
return true;
}
}
runWithScissors保留