【Android消息机制】简要分析(一)

主要组成概述:Hanlder、MessageQueue以及Looper

1.Handler:线程切换

2.MessageQueue:用来存储信息 内部实现是单链表而不是队列。

3.Looper:无限循环的方式去查找是否有消息

备注:Looper中一个ThreadLocal的概念
作用:是来存储每一个线程中数据。
用途:Hanlder创建的时候会采用当前线程的Looper来构造消息循环系统,Handler正式通过ThreadLocal来获取当前的线程Looper的。

源代码

1.Handler是如何将三者联系起来的?

看看Handler创建源代码:

public Handler(Callback callback, boolean async) {
        ...//省略
        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;
    }

到调用了Looper.myLooper()

我们点进看看:

   /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static Looper myLooper() {
        return sThreadLocal.get();
    }

没错,的确是这样印证了Handler、Looper的关系。

那么MessageQueue是如何一起协同工作呢?

我们看到mQueue = mLooper.mQueue;

所以从不难推断出MessageQueue在Looper初始化的时候也一并初始化了。

从这里我们也可以看出:无论我们在主线程创建多少个Handler,他们公用一个消息队列的

2.Looper是如何工作的?

上面概述的时候我们知道,Looper是负责从消息队列中读取消息,然后回传到handler的handleMessage方法来处理消息的。

大家不知道还记不记得,我们是如何在子线程创建一个Handler的? 我们需要调用Looper.prepare()来准备一个Looper,并且调用Looper.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();
        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;
            }

           ...

            msg.target.dispatchMessage(msg);

            ...


        }
    }

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static Looper myLooper() {
        return sThreadLocal.get();
    }

第一步:先调用了Looper.myLooper()这个方法,返回当前线程所在的Looper实例。备注:这里也刚好可以看到了ThreadLocal的用途了。

第二步:无限死循环 如果有消息来了就:msg.target.dispatchMessage(msg);

这个msg.target是什么呢? 通过Message源代码发现 就是发送这个msg对象的Handler实例: Handler target;

那msg是什么时候保存的呢?通过Handler源代码发现:

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

msg在入队前,保存了这个handler实例的引用。

然后调用了这个Hanlder实例的dispatchMessage的方法。

那我们来看看Handler的dispatchMessage做了什么:

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

我们看到一句很重点的:handleMessage(msg);
实际上他是一个空方法:

    public void handleMessage(Message msg) {
    }

这个就是为什么我们创建Handler之后要重写这个方法来处理消息了。

-Hans 2016.2.25 23:45

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值