一、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 方法

更多相关文章

  1. Android 为什么主线程的looper 一直循环不会ANR
  2. Android进阶-Android Handler消息机制的源码详解
  3. 关于Android中的消息机制和异步
  4. Android消息循环的同步屏障机制及UI渲染性能的提升(Android Q)
  5. Android使用Sensor感应器实现线程中刷新UI创建android测力计的功
  6. Android引入广播机制的用意。单线程模型Message、Handler、Messa
  7. UWP与Android中如何在多线程中刷新UI
  8. android中异步消息的处理机制
  9. Android BroadcastReceiver(广播)实现消息发送

随机推荐

  1. MySQL数据库的实时备份知识点详解
  2. CentOS安装配置MySQL8.0的步骤详解
  3. Mysql下自动删除指定时间以前的记录的操
  4. 深入浅出讲解MySQL的并行复制
  5. MacBook下python3.7安装教程
  6. Windows7下Python3.4使用MySQL数据库
  7. mysql遇到load data导入文件数据出现1290
  8. Mysql指定日期区间的提取方法
  9. mysql 8.0.11 macos10.13安装配置方法图
  10. mysql 5.6.23 安装配置环境变量教程