Android(安卓)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.
1.Handler 允许您发送和处理 和线程关联的 Message和Runnable 对象
2.每个handler 实例都和一个线程和 线程队列 关联
3.当你创建一个handler 实例的时候,都会和创建它的线程以及线程队列绑定,它会将message/runnable 对象传到message queue,在message/runnable 对象取出的时候会执行他们
4.handler 两个用途:1.在未来(延迟)执行message/runnable 2.切换线程
5.消息调度通过 以下方法
{@link #post}, {@link #postAtTime(Runnable, long)}, * {@link #postDelayed}, {@link #sendEmptyMessage}, * {@link #sendMessage}, {@link #sendMessageAtTime}, and * {@link #sendMessageDelayed} methods.
将message/runnable 对象排到message queue中
6.sendMessage中的 message 对象可以包含 一些数据,最终传递到handler 的 handlMessage 处理
7.当通过post 或者send 发送消息时,可以立即执行,也可以在指定延迟的时间或者指定时间或者其他相关时间执行
8.当为你的app 创建进程的时候,它的主线程专用于管理最高级别的app对象(activity,broadcast receivers etc)以及创建的任何widnow。你可以创建自己的线程,并通过handler 与主线程通信(在你的线程中调用 handler 的post/send 方法,message/runnable 对象会排进线程的message queue,并在合适的时候被执行)
二、源码 将消息传到 message queue
/** * 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 绑定的线程执行,如果成功加到队列返回true ,失败则返回false,通常looper 在退出的时候会失败
/** * 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); }
将message/runnable 对象在延迟delayMillis 时间后加在所有待处理的消息后面,如果成功加入消息队列返回true,失败返回false 当looper 正在退出的时候会失败。但加入成功不一定意味着它一定会被执行,如果在执行它之前 looper 退出,那么它将会被丢弃不会被执行。
/** * 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); }
上面几段的注释都差不多,这里加了:深度睡眠会给执行增加额外的延迟
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
注意:msg.target = this
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; }
这段是 messageQueue 的方法,就是将 消息加到队列里面
以上就是将消息放到 消息队列的过程
三、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, 会抛出异常。
/** * 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; }
handler 默认都是同步的除非在构造方法的参数指定为 异步的,异步消息不会参与全局排序,也不受中断的影响??
1.如果handler (匿名内部类/成员变量/局部变量)被修饰成static 会提示 有泄漏的可能
handler 的messagequeue = looper 的 messsagequeue
Looper相关
** * Class used to run a message loop for a thread. Threads by default do * not have a message loop associated with them; to create one, call * {@link #prepare} in the thread that is to run the loop, and then * {@link #loop} to have it process messages until the loop is stopped. * * Most interaction with a message loop is through the * {@link Handler} class. * *
This is a typical example of the implementation of a Looper thread, * using the separation of {@link #prepare} and {@link #loop} to create an * initial Handler to communicate with the Looper. * *
* class LooperThread extends Thread { * public Handler mHandler; * * public void run() { * Looper.prepare(); * * mHandler = new Handler() { * public void handleMessage(Message msg) { * // process incoming messages here * } * }; * * Looper.loop(); * } * }
*/
Looper 用来管理线程的消息循环的,线程默认没有线程循环(looper);为线程创建消息循环 需要调用 Looper.prepare() 之后调用Looper.loop()开启循环直到循环停止,大多数都是通过handler 来操作消息循环的
/** Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference * this looper, before actually starting the loop. Be sure to call * {@link #loop()} after calling this method, and end it by calling * {@link #quit()}. */ public static void prepare() { prepare(true); }
为当前线程创建线程循环,这个方法让你在开启循环之前可以创建handler 然后引用它,在prepare() 之后 调用loop()开启消息循环,quit() 方法退出循环。
private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
/** * Returns the value in the current thread's copy of this * thread-local variable. If the variable has no value for the * current thread, it is first initialized to the value returned * by an invocation of the {@link #initialValue} method. * * @return the current thread's value of this thread-local */ public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
ThreadLocal 通过 thread 的 threadLocalMap 维护 Thread 和 looper 对象,类似map
static final ThreadLocal sThreadLocal = new ThreadLocal();
Looper 类有个常量
private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
可以看出一个线程可能有很多个 threadLocals ,通过threadlocal 可以将线程和各种数据绑定 实现数据在每个线程有不同的值,这里绑定的looper
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs; final long traceTag = me.mTraceTag; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); final long end; try { msg.target.dispatchMessage(msg); end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } if (slowDispatchThresholdMs > 0) { final long time = end - start; if (time > slowDispatchThresholdMs) { Slog.w(TAG, "Dispatch took " + time + "ms on " + Thread.currentThread().getName() + ", h=" + msg.target + " cb=" + msg.callback + " msg=" + msg.what); } } if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycleUnchecked(); } }
looper.loop() 开启了一个死循环 当 messagequeue.next()返回 null 的时候会退出否则 会调用 msg.target.dispatchMessage(msg)
方法,上面提到 msg.target 在加到队列之前 被赋值为 handler 所以这里就是调用 handler 的方法
/** * 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); } }
如果Message 设置了callback
private static void handleCallback(Message message) { message.callback.run(); }
如果没设置,如果handler设置了callback 会回调callback 的方法。然后调用 handler 的 handleMessage 方法
关于looper 的停止
quit()实际上是把消息队列全部清空,然后让MessageQueue.next()返回null令Looper.loop()循环结束从而终止Handler机制
,但是存在着不安全的地方是可能有些消息在消息队列没来得及处理。而quitsafely()
做了优化,只清除消息队列中延迟信息,等待消息队列剩余信息处理完之后再终止Looper
循环。
思考:handler 的removeCallbacksAndMessages(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); }
void removeCallbacksAndMessages(Handler h, Object object) { if (h == null) { return; } synchronized (this) { Message p = mMessages; // Remove all messages at front. while (p != null && p.target == h && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycleUnchecked(); p = n; } // Remove all messages after front. while (p != null) { Message n = p.next; if (n != null) { if (n.target == h && (object == null || n.obj == object)) { Message nn = n.next; n.recycleUnchecked(); p.next = nn; continue; } } p = n; } } }
当token == null 的时候是移除并回收了所有的message,不为null 只是移除回收了指定的message,并不会停止looper();
所以在不需要该thread中创建的Handler时,要调用looper.quit(),结束消息队列,进而结束线程。如果不这么做,thread会长时间存在不销毁。
总结:
1.handler 用来处理延时任务或者线程切换
2.流程:handler 是通过looper 来管理消息循环的
消息循环:在线程中使用handler 的时候需要先 调用Looper.prepare() 初始化looper ,然后调用loop()开启循环
loop()==>Messagequeue.next() 从looper 的messagequeue 取出消息 ==》handler.dispatchMessage(msg)==》handleMessage(msg)
添加消息:handler.post/send 将message 加到队列里面
退出:looper.quit()
对于Runable 对象也是封装成Message 来使用的
/** * 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); }
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
最终执行了 runnable 的run 方法
更多相关文章
- Android(安卓)为什么主线程的looper 一直循环不会ANR
- Android(安卓)多媒体录制
- Android消息循环的同步屏障机制及UI渲染性能的提升(Android(安卓)
- 《Effieicntt Android(安卓)Threading》 Chapter4 -- Thread Com
- 关于Android中的消息机制和异步
- Android进阶-Android(安卓)Handler消息机制的源码详解
- Android(安卓)View 的刷新机制
- 十分钟让你了解Android触摸事件原理(InputManagerService)
- Android电话来电流程源码分析