Looper

   2016-09-08 0
核心提示:这个类用于为线程运行一个消息循环. 默认上, 线程是没有与之绑定的消息循环的. 为了创建一个消息循环, 在线程中调用 prepare 方法来创建一个循环, 之后调用 loop 方法启动循环, 开始处理消息, 直到循环停止.大多数与 Loop 有关的交互都是通过 Handler 类来实

这个类用于为线程运行一个消息循环. 默认上, 线程是没有与之绑定的消息循环的. 为了创建一个消息循环, 在线程中调用 prepare 方法来创建一个循环, 之后调用 loop 方法启动循环, 开始处理消息, 直到循环停止.

大多数与 Loop 有关的交互都是通过 Handler 类来实现的.

下面给出一个最典型的实现 Looper 的线程. 使用单独的 prepare 和 loop 来创建一个初始 Handler 来与 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();
    }
}

数据结构

ThreadLocal

ThreadLocal 中存放 Looper:

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

ThreadLocal: 线程本地存储区(Thread Local Storage,简称为TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的TLS区域。这里线程自己的本地存储区域存放是线程自己的Looper。具体看下ThreadLocal.java 的源码!

sMainLooper

MainLooper 整个应用程序里面只有一个. 应用程序的 MainLooper 是由 Android 环境创建的. 因此开发者不应当调用 prepareMainLooper 方法.

private static Looper sMainLooper;

static 修饰符

注意到 sThreadLocal 和 sMainLooper 都是 static 的.

类的 static 成员说明所有的类实例中这两个成员都只有==一份==.

sThreadLocal 这块可以好好看看, 它也是 static 的, 它内部保存到是各个线程的 Looper 实例. ThreadLocal 只有一个接口 get, 每个线程都通过这个方法拿到自己的 Looper.

mQueue

final MessageQueue mQueue;

这个就不是 static 的了, 这是每个 Looper 实例自己有一份的.

MessageQueue 等着单独分析.

这里只要确定一点:== Looper 中包含 MessageQueue 消息队列.==

mThread

final Thread mThread;

这个成员保存了 Looper 实例所处的 Thread 线程的实例.

用到这个实例的地方有:

  • 构造函数中 Thread.currentThread()
  • getThread 获取线程

方法

prepare 系列

将当前线程初始化为 Looper. prepare 给予你机会在 Looper 真正运行之前来创建 Handler 并引用到这个 Looper. 在这之后, 需要调用 loop() 方法来使 Looper 运行, 最后调用 quit() 方法来退出.

prepare 方法有两个, 带参数和不带参数的:

public static void prepare()
private static void prepare(boolean quitAllowed)

还有一个初始化 MainLooper 的:

public static void prepareMainLooper()

MainLooper 和普通 Looper 的初始化进本是类似的, 创建一个 Looper 实例并保存至 ThreadLocal 类型的 sThreadLocal 中. MainLooper 比普通 Looper 再多一步的操作是将 Looper 实例的引用保存到 sMainLooper 成员中.

getter 方法

前面分析了两种 Looper 的创建, 现在来看看它们的获取方法:

  • public static @Nullable Looper myLooper()
  • public static Looper getMainLooper()

一个是获取普通 Looper 的, 一个是获取 MainLooper 的.

loop() 运行循环

代码的实现非常清晰:

public static void loop() {
    // 获取 Looper
    final Looper me = myLooper();
    // 获取消息队列
    final MessageQueue queue = me.mQueue;

    // 死循环
    for (;;) {
        // 获取下一条消息
        Message msg = queue.next(); // 可能会阻塞

        // 消息为空说明队列正在推出, 因此直接退出
        if (msg == null) return;

        // msg.target 是一个 Handler, 因此分发这个消息
        msg.target.dispatchMessage(msg);

        // 回收消息
        msg.recycleUnchecked();
    }
}
 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • Handler机制从入门到放弃(二)
    Handler机制从入门到放弃(二)
    Hander的源码只有不到800行,而且大多数代码相对来说还是比较好理解的,尤其是相对于其他更加接近底层的代码来说,在看源码时候有一点挺重要的就是不要忽略注释的作用,Handler类开头有这么几行注释: pThere are two main uses for a Handler: (1) to schedu
  • Android 一些面试问题收集
    前言因为最近换工作,所以需要面试,但是面试了3家只有一个offer,只是可能因为工资问题最终还是需要继续面试,同时感觉每次面试都不做任何准备,不看面试题,不去温习一下书本,感觉临场表现可能的确不行吧,所以本文主要记录在面试中被遇到的一些问题和一些
点击排行