设为首页 加入收藏

TOP

深入理解 Handler 消息机制(四)
2019-09-06 00:27:03 】 浏览:145
Tags:深入 理解 Handler 消息 机制
.. }

prepareMainLooper()

public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

sMainLooper 只能被初始化一次,也就是说 prepareMainLooper() 只能调用一次,否则将直接抛出异常。

prepare()

public static void prepare() {
        prepare(true);
}

private static void prepare(boolean quitAllowed) {
    // 每个线程只能执行一次 prepare(),否则会直接抛出异常
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    // 将 Looper 存入 ThreadLocal
    sThreadLocal.set(new Looper(quitAllowed));
}

主线程中调用的是 prepare(false),说明主线程 Looper 是不允许退出的。因为主线程需要源源不断的处理各种事件,一旦退出,系统也就瘫痪了。而我们在子线程调用 prepare() 来初始化 Looper时,默认调动的是 prepare(true),子线程 Looper 是允许退出的。

每个线程的 Looper 是通过 ThreadLocal 来存储的,保证其线程私有。

再回到文章开头介绍的 Handler 的构造函数中 mLooper 变量的初始化:

mLooper = Looper.myLooper();
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

也是通过当前线程的 ThreadLocal 来获取的。

构造函数

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

再对照 Handler 的构造函数:

public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

其中的关系就很清晰了。

  • Looper 持有 MessageQueue 对象的引用
  • Handler 持有 Looper 对象的引用以及 Looper 对象的 MessageQueue 的引用

loop()

看到这里,消息队列还没有真正的运转起来。我们先来看一个子线程使用 Handler 的标准写法:

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.loop()

public static void loop() {
    final Looper me = myLooper(); // 从 ThreadLocal 中获取当前线程的 Looper
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue; // 获取当前线程的消息队列

   ...  // 省略部分代码

    for (;;) { // 循环取出消息,没有消息的时候可能会阻塞
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

        ...  // 省略部分代码
       

        try {
            msg.target.dispatchMessage(msg); // 通过 Handler 分发 Message
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }

        ...  // 省略部分代码

        msg.recycleUnchecked(); // 将消息放入消息池,以便重复利用
    }
}

简单说就是一个死循环不停的从 MessageQueue 中取消息,取到消息就通过 Handler 来进行分发,分发之后回收消息进入消息池,以便重复利用。

从消息队列中取消息调用的是 MessageQueue.next() 方法,之前已经分析过。在没有消息的时候可能会阻塞,避免死循环消耗 CPU。

取出消息之后进行分发调用的是 msg.target.dispatchMessage(msg)msg.target 是 Handler 对象,最后再来看看 Handler 是如何分发消息的。

public void dispatchMessage(Message msg) {
    if (msg.callback != null) { // callback 是 Runnable 类型,通过 post 方法发送
        handleCallback(msg);
    } else {
        if (mCallback != null) { // Handler 的 mCallback参数 不为空时,进入此分支
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg); // Handler 子类实现的  handleMessage 逻辑
    }
}

private static void handleCallback(Message message) {
    message.callback.run();
}
  • Message 的 callback 属性不为空时,说明消息是通过 postXXX() 发送的,直接执行 Runnable 即可。
  • Handler 的 mCallback 属性不为空,说明构造函数中传入了 Callback 实现,调用 mCallback.handleMessage(msg) 来处理消息
  • 以上条件均不满足,只可能是 Handler 子类重写了 handleMessag
首页 上一页 1 2 3 4 5 下一页 尾页 4/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇基于wanAndroid-项目实战 下一篇Android几种多渠道打包

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目