• Android源码学习(2) Handler之Looper


    Looper准备

    Handler实例化时,会从当前线程获取Looper,从而获得MessageQueue,用于发送消息。然而,线程不是生来就有Looper对象的,需要在线程执行中调用静态方法Looper.prepare(),最终会调用到如下静态方法:

    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));
    }

    静态变量sThreadLocal是范型类ThreadLocal<Looper>的实例,用于保存线程与其Looper之间的映射关系:sThreadLocal以自身为key,将Looper实例放入当前线程的ThreadLocalMap中(字段名为threadlocals,ThreadLocalMap底层是通过hash表实现的)。由于任何线程存放Looper都是以sThreadLocal为key,所以任意线程最多只能有一个Looper。

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }

    Looper循环

    准备完成之后,通过调用Looper.loop()进入looper循环。Looper在死循环中,不断从MessageQueue中获取消息,交给Handler的dispatchMessage进行处理。loop函数的关键代码是黄色背景标记的区域:

     1 public static void loop() {
     2     final Looper me = myLooper();
     3     if (me == null) {
     4         throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
     5     }
     6     final MessageQueue queue = me.mQueue;
     7 
     8     // Make sure the identity of this thread is that of the local process,
     9     // and keep track of what that identity token actually is.
    10     Binder.clearCallingIdentity();
    11     final long ident = Binder.clearCallingIdentity();
    12 
    13     for (;;) {
    14         Message msg = queue.next(); // might block
    15         if (msg == null) {
    16             // No message indicates that the message queue is quitting.
    17             return;
    18         }
    19 
    20         // This must be in a local variable, in case a UI event sets the logger
    21         final Printer logging = me.mLogging;
    22         if (logging != null) {
    23             logging.println(">>>>> Dispatching to " + msg.target + " " +
    24                     msg.callback + ": " + msg.what);
    25         }
    26 
    27         final long traceTag = me.mTraceTag;
    28         if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
    29             Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
    30         }
    31         try {
    32             msg.target.dispatchMessage(msg);
    33         } finally {
    34             if (traceTag != 0) {
    35                 Trace.traceEnd(traceTag);
    36             }
    37         }
    38 
    39         if (logging != null) {
    40             logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
    41         }
    42 
    43         // Make sure that during the course of dispatching the
    44         // identity of the thread wasn't corrupted.
    45         final long newIdent = Binder.clearCallingIdentity();
    46         if (ident != newIdent) {
    47             Log.wtf(TAG, "Thread identity changed from 0x"
    48                     + Long.toHexString(ident) + " to 0x"
    49                     + Long.toHexString(newIdent) + " while dispatching to "
    50                     + msg.target.getClass().getName() + " "
    51                     + msg.callback + " what=" + msg.what);
    52         }
    53 
    54         msg.recycleUnchecked();
    55     }
    56 }

    每个Message被处理完之后,会被自动回收,放回Message池中。

    Looper退出

    通过调用quit或者quitSafely退出Looper循环。底层是调用MessageQueue的quit函数实现:

     1 void quit(boolean safe) {
     2     if (!mQuitAllowed) {
     3         throw new IllegalStateException("Main thread not allowed to quit.");
     4     }
     5 
     6     synchronized (this) {
     7         if (mQuitting) {
     8             return;
     9         }
    10         mQuitting = true;
    11 
    12         if (safe) {
    13             removeAllFutureMessagesLocked();
    14         } else {
    15             removeAllMessagesLocked();
    16         }
    17 
    18         // We can assume mPtr != 0 because mQuitting was previously false.
    19         nativeWake(mPtr);
    20     }
    21 }

    quit调用removeAllMessageLocked,该函数会直接移除MessageQueue中所有尚未处理的Message;quitSafely调用removeAllFutureMessageLocked,该函数只会移除执行时刻晚于当前时刻的Message(即,Message.when > now)。

  • 相关阅读:
    需求用例分析之七:业务用例之小结
    [Hibernate开发之路](4)ID生成策略
    Selenium基于Python 进行 web 自动化测试
    四个修改Docker默认存储位置的方法
    centos中文字符集,中文日志
    LVS管理工具ipvsadm详解与LVS-NAT模式演示
    mysql查看锁表情况
    centos7使用kubeadm配置高可用k8s集群
    LVS+keepalived+nginx+tomcat
    LVS_DR模式构建配置
  • 原文地址:https://www.cnblogs.com/moderate-fish/p/7652154.html
Copyright © 2020-2023  润新知