#开篇

#核心源码

#简述

在整个 Android 的源码世界里,有两大利剑,其一是 Binder 机制,另一个便是 Handler 消息机制。消息机制涉及**MessageQueue/Message/Looper/Handler **这4个类。

Handler 是 Android 中引入的一种让开发者参与处理线程中消息循环的机制。我们在使用 Handler 的时候与 Message 打交道最多,Message 是 Hanlder 机制向开发人员暴露出来的相关类,可以通过 Message 类完成大部分操作 Handler 的功能。

作为一名程序员,我们不仅需要知道怎么用 Handler ,还要知道其内部如何实现的,这就是我写这篇文章的目的。
#模型

#####消息机制(Handler)主要包含:

    ✨ Message:消息分为硬件产生的消息(如按钮、触摸)和软件生成的消息;    ✨ MessageQueue:消息队列的主要功能向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next);    ✨ Handler:消息辅助类,主要功能向消息池发送各种消息事件(Handler.sendMessage)和处理相应消息事件(Handler.handleMessage);    ✨ Looper:不断循环执行(Looper.loop),按分发机制将消息分发给目标处理者。

#实例

 * 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

消息队列 MessageQueue 只是存储 Message 的地方,真正让消息队列循环起来的是 Looper,我们先来重点分析 Looper。

Looper 是用来使线程中的消息循环起来的。默认情况下当我们创建一个新的线程的时候,这个线程里面是没有消息队列 MessageQueue 的。为了能够让线程能够绑定一个消息队列,我们需要借助于 Looper :首先我们要调用 Looper 的 prepare() 方法,然后调用 Looper 的 Loop() 方法。

需要注意的是 Looper.prepare() 和 Looper.loop() 都是在新线程的 run 方法内调用的,这两个方法都是静态方法。

public static void prepare() {...}    private static void prepare(boolean quitAllowed) {...}    public static void loop() {...}

#1.prepare()

我们来看一下 Looper.prepare(),该方法是让 Looper 做好准备,只有 Looper 准备好了之后才能调用 Looper.loop() 方法。

public static void prepare() {            prepare(true);     // 无参,调用 prepare(boolean quitAllowed)    }
private static void prepare(boolean quitAllowed) {        if (sThreadLocal.get() != null) {        // 每个线程只允许执行一次该方法,第二次执行时已有 Looper,则会抛出异常!            throw new RuntimeException("Only one Looper may be created per thread");        }        // 创建 Looper 对象,并保存到当前线程的本地存储区        sThreadLocal.set(new Looper(quitAllowed));          }

上面的代码首先通过 sThreadLocal.get() 拿到线程 sThreadLocal 所绑定的 Looper 对象,由于初始情况下 sThreadLocal 并没有绑定 Looper ,所以第一次调用 prepare 方法时,sThreadLocal.get() 返回 null,不会抛出异常。

####2.ThreadLocal
ThreadLocal:线程本地存储区(Thread Local Storage,简称为 TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的TLS区域。

TLS 常用的操作方法:

####3.set()

public void set(T value) {        Thread t = Thread.currentThread();    // 获取当前线程         ThreadLocalMap map = getMap(t);       //查找当前线程的本地储存区        if (map != null)            map.set(this, value);             // 保存数据 value 到当前线程 this        else            createMap(t, value);    }

######我们看下 getMap() 函数:

 ThreadLocalMap getMap(Thread t) {        return t.threadLocals;    }

######判断 map 是否为空,如果为空则创建 ThreadLocalMap :

 void createMap(Thread t, T firstValue) {        t.threadLocals = new ThreadLocalMap(this, firstValue);    }

####4.get()

private T setInitialValue() {        T value = initialValue();        Thread t = Thread.currentThread();        ThreadLocalMap map = getMap(t);        if (map != null)            map.set(this, value);        else            createMap(t, value);        return value;    }

######Looper 通过如下代码保存了对当前线程的引用:

static final ThreadLocal sThreadLocal = new ThreadLocal(); // sThreadLocal 为 ThreadLocal 类型

所以在 Looper 对象中通过 sThreadLocal 就可以找到其绑定的线程。ThreadLocal 中有个 set 方法和 get 方法,可以通过 set 方法向 ThreadLocal 中存入一个对象,然后可以通过 get 方法取出存入的对象。

ThreadLocal 在 new 的时候使用了泛型,从上面的代码中我们可以看到此处的泛型类型是 Looper ,也就是我们通过 ThreadLocal 的 set 和 get 方法只能写入和读取 Looper 对象类型。

#二 构造函数
源码中 Looper 的构造函数是 private 的,也就是在该类的外部不能用 new Looper() 的形式得到一个 Looper 对象。

private Looper(boolean quitAllowed) {...}

######我们看下上面代码中 new Looper() 创建 Looper 对象的工作:

private Looper(boolean quitAllowed) {    mQueue = new MessageQueue(quitAllowed);  // 创建 MessageQueue 对象    mThread = Thread.currentThread();        // 记录当前线程}

Looper.prepare()在每个线程只允许执行一次,该方法会创建 Looper 对象,Looper 的构造方法中会创建一个 MessageQueue 对象,再将 Looper 对象保存到当前线程 TLS。
#1.prepareMainLooper()

另外,与 prepare() 相近功能的,还有一个 prepareMainLooper() 方法,该方法主要在 ActivityThread 类中使用。

public static void prepareMainLooper() {        prepare(false);          // 设置不允许退出的 Looper        synchronized (Looper.class) {            // 将当前的 Looper 保存为主 Looper,每个线程只允许执行一次            if (sMainLooper != null) {                throw new IllegalStateException("The main Looper has already been prepared.");            }            sMainLooper = myLooper();        }    }

#2.loop()
Looper.loop()的代码如下:

 /**     * 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();            // 获取当前线程绑定的 Looper 对象        if (me == null) {            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");        }        final MessageQueue queue = me.mQueue;    // 获取 Looper 对象中的消息队列        // 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 (;;) {     // 进入loop的主循环方法            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            // 默认为null,可通过 setMessageLogging() 方法来指定输出,用于 debug 功能            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);       // 用于分发 Message                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();     // 确保分发过程中 identity 不会损坏            if (ident != newIdent) {                // 打印 identity 改变的 log,在分发消息过程中是不希望身份被改变的            }            msg.recycleUnchecked();   // 将 Message 放入消息池        }    }

我们接下来会重点分析 loop() 里面的几个函数:
#####myLooper()
前面我们说过,在执行完了 Looper.prepare() 之后,我们就可以在外部通过调用 Looper.myLooper() 获取当前线程绑定的 Looper 对象。

public static @Nullable Looper myLooper() {        return sThreadLocal.get();      // 还是通过 sThreadLocal.get()方法获取当前线程绑定的 Looper 对象    }

####3.MessageQueue

// Looper 构造函数中创建了 mQueue,即 MessageQueueprivate Looper(boolean quitAllowed) {    mQueue = new MessageQueue(quitAllowed);  // 创建 MessageQueue 对象    mThread = Thread.currentThread();        // 记录当前线程}
 public static void loop() {        final Looper me = myLooper();             // 获取当前线程绑定的 Looper 对象        if (me == null) {            ... ...        }        final MessageQueue queue = me.mQueue;     // 获取 Looper 对象中的消息队列

变量 me 是通过静态方法 myLooper() 获得的当前线程所绑定的 Looper,me.mQueue 就是当前线程所关联的消息队列。
####4.for()

for (;;) { // 进入loop的主循环方法

我们发现for循环没有设置循环终止的条件,所以这个for循环是个死循环。

####5.Message

Message msg = queue.next(); // might block

我们通过消息队列 MessageQueue 的 next 方法从消息队列中取出一条消息,如果此时消息队列中有 Message,那么 next 方法会立即返回该 Message,如果此时消息队列中没有 Message,那么 next 方法就会阻塞式地等待获取 Message。

####6.dispatchMessage()

/*package*/ Handler target;
try {    msg.target.dispatchMessage(msg);    end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();} finally {    if (traceTag != 0) {        Trace.traceEnd(traceTag);    }}

msg 的 target 属性是 Handler,该代码的意思是让 Message 所关联的 Handler 通过 dispatchMessage 方法让 Handler 处理该 Message ,关于 Handler 的 dispatchMessage 方法将会在下面详细介绍。

####7.recycleUnchecked()

msg.recycleUnchecked(); // 分发后的 Message 回收到消息池,以便重复利用

#小结
loop()进入循环模式,不断重复下面的操作,直到没有消息时退出循环:

####1、读取 MessageQueue 的下一条 Message;
####2、把 Message 分发给相应的 target;
####3、再把分发后的 Message 回收到消息池,以便重复利用。
明天继续更完剩下的

#想学习更多Android知识,或者获取相关资料请加入Android技术开发交流2群:935654177。本群可免费获取Gradle、RxJava、小程序、Hybrid、移动架构、NDK、React Native、性能优化等技术教程!

更多相关文章

  1. android service(一)
  2. 浅谈Android(安卓)Handler 消息机制
  3. Android(安卓)MultiDex
  4. Android(安卓)System.exit(code) and android.os.Process.killPr
  5. 【Android】模拟点击探索
  6. Android(安卓)Jetpack架构组件(二)带你了解Lifecycle(使用篇)
  7. CSDN日报190904:Android(安卓)10正式版发布,看看都有哪些新特性
  8. Android(安卓)远程图片获取和本地缓存(一)
  9. Android之使用SAX方式解析XML文件

随机推荐

  1. 使用Eclipse开发Android时整个工程或第三
  2. Android常用布局之LinearLayout(线性布局
  3. 麦子学院Android应用开发工程师视频教程
  4. Android(安卓)Studio开发环境的搭建
  5. Android中的人脸检测(静态和动态)
  6. Android(安卓)状态栏通知Notification(转
  7. Android(安卓)的属性系统
  8. Android(安卓)Handler机制8之消息的取出
  9. padding和margin的区别及其属性
  10. Android源码博文集锦2