Handler机制详解

来源:互联网 发布:java爬虫技术视频教程 编辑:程序博客网 时间:2024/05/29 13:52

相信大部分android开发者使用Handler已经滚瓜烂熟了,但是当你不去深入研究它的原理,不去理清它与Looper和Message之间的关系时,遇到问题和bug的时候你就会无从下手,手忙脚乱。

技术是一门学问,只知其一不知其二,你永远只会停留在基础。所以我们就看看源码,好好研究一些底层的到底做了什么:

Handler运行机制梳理

我们在使用Handler的时候,往往是这样一个使用步骤:

1.    初始化一个Handler对象,重写其handleMessage方法

2.    获取一个Message对象,并相应的为其what、obj属性赋值

3.    调用Handler.sendMessage(msg)方法发送消息

4.    发送出来的消息,将在Handler的handleMessage方法中进行处理

  因此,我们从sendMessage方法看Handler执行了什么逻辑:

源码路径:frameworks\base\core\java\android\os\Handler.java

    public final boolean sendMessage(Message msg)

    {

        return sendMessageDelayed(msg, 0);

}

 

……

 

    public final boolean sendMessageDelayed(Message msg, long delayMillis)

    {

        if (delayMillis < 0) {

            delayMillis = 0;

        }

        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);

}

 

……

 

    public boolean sendMessageAtTime(Message msg, long uptimeMillis)

    {

        boolean sent = false;

        MessageQueue queue = mQueue;

        if (queue != null) {

            msg.target = this;

            sent = queue.enqueueMessage(msg, uptimeMillis);

        }

        else {

            RuntimeException e = new RuntimeException(

                this + " sendMessageAtTime() called with no mQueue");

            Log.w("Looper", e.getMessage(), e);

        }

        return sent;

    }

 

由代码可知,sendMessage和sendMessageDelayed实际上都是调用了sendMessageAtTime方法。

若是采用sendMessage方法发送的消息,则uptimeMillis的值=当前时间;

若采用sendMessageAtTime方法发送消息,则uptimeMillis的值=当前时间+ delayMillis。

 

注意“msg.target = this;”这行代码,this在这里指的自然是发送这个Message的Handler对象,这行代码非常重要,在后面我们会遇到。


最终,我们是通过“queue.enqueueMessage(msg,uptimeMillis);”这行代码将Message塞入了一个MessageQueue对象中,我们看看这个方法又做了什么:

frameworks\base\core\java\android\os\MessageQueue.java

final boolean enqueueMessage(Message msg, long when) {

        ……

        synchronized (this) {

            ……

            msg.when = when;

            //Log.d("MessageQueue", "Enqueing: " + msg);

            Message p = mMessages;

            if (p == null || when == 0 || when < p.when) {

                msg.next = p;

                mMessages = msg;

                needWake = mBlocked; // new head, might need to wake up

            } else {

                Message prev = null;

                while (p != null && p.when <= when) {

                    prev = p;

                    p = p.next;

                }

                msg.next = prev.next;

                prev.next = msg;

                needWake = false; // still waiting on head, no need to wake up

            }

        }

        ……       

return true;

    }

 

以上代码只做了一件事,将我们的Message加入到MessageQueue中,并根据when这个时间值对我们的MessageQueue中的Message进行了排序。

这个when值,就是之前我们传进来的那个uptimeMillis。


那么,消息被放到了我们的MessageQueue中,又由谁来取出并分发呢?

答案是我们的Looper。


我们的应用程序启动,主线程开启时,系统会创建一个Looper,并调用其loop方法,使其开始轮询MessageQueue中的消息:

frameworks\base\core\java\android\app\ActivityThread.java

public static final void main(String[] args) {

        ……

        Looper.prepareMainLooper();

        ……

        Looper.loop();

        ……

}

 

 

frameworks\base\core\java\android\os\Looper.java

    public static final void prepareMainLooper() {

        prepare();

        setMainLooper(myLooper());

……

    }

……

    public static final void prepare() {

        if (sThreadLocal.get() != null) {

            throw new RuntimeException("Only one Looper may be created per thread");

        }

        sThreadLocal.set(new Looper());

}

……

    public static final Looper myLooper() {

        return (Looper)sThreadLocal.get();

    }

……

public static final void loop() {

        Looper me = myLooper();

        MessageQueue queue = me.mQueue;

        while (true) {

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

            if (msg != null) {

                if (msg.target == null) {

                   return;

                }

                ……

                msg.target.dispatchMessage(msg);

                ……

            }

        }

    }

 

Loop方法实际上是维持着一个死循环,他不停的从MessageQueue中取到Message并将Message分发。

当MessageQueue中没有消息时,Loop会处于阻塞状态:

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

 

Message被分发的代码为:

msg.target.dispatchMessage(msg);

 

这里的msg.target,即发送我们这个Message的Handler对象,因此,这行代码还是调用回了我们的Handler的dispatchMessage方法:


frameworks\base\core\java\android\os\Handler.java 

    public void dispatchMessage(Message msg) {

        if (msg.callback != null) {

            handleCallback(msg);

        } else {

            if (mCallback != null) {

                if (mCallback.handleMessage(msg)) {

                    return;

                }

            }

            handleMessage(msg);

        }

    }

 

由代码可知,我们通过Handler发送的消息,最终由我们Handler的handleMessage方法来进行处理,Handler的这一套运行机制到此完毕。


好了,整个运行机制我们走通了,那么我们再来想一个问题:

Handler机制靠什么保证消息不混乱

假如现在我们new了10几个Handler,同时去sendMessage,我们如何保证哪个Handler发送的消息,就交由哪个Handler的handleMessage方法去处理?


牢记我们发送消息和分发消息的时候的这2行代码:

frameworks\base\core\java\android\os\Handler.java

public boolean sendMessageAtTime(Message msg, long uptimeMillis)

    {

        boolean sent = false;

        MessageQueue queue = mQueue;

        if (queue != null) {

            msg.target = this;

            sent = queue.enqueueMessage(msg, uptimeMillis);

        }

        ……

        return sent;

    }

 

frameworks\base\core\java\android\os\Looper.java

    public static final void loop() {

        Looper me = myLooper();

        MessageQueue queue = me.mQueue;

        while (true) {

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

            if (msg != null) {

                if (msg.target == null) {

                   return;

                }

                ……

                msg.target.dispatchMessage(msg);

                ……

            }

        }

    }

 

通过这个“msg.target”,我们就可以保证:哪个Handler发送的消息,哪个Handler来处理。Google这么设计是不是什么巧妙?


相信细心的朋友 在源码中看到这么一个变量 : sThreadLocal,他其实是一个ThreadLocal类型的变量,那么ThreadLocal又是个什么东西呢? 我们来说一说:

ThreadLocal

ThreadLocal就是线程局部变量,经常使用此方法保存线程内的共享变量。

同一个线程内的多个不同的类,可以通过ThreadLocal来共享全局变量。

当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作。

 

所有在主线程new出来的Handler,最后都是通过ThreadLocal取用主线程创建的那个Looper,来实现的消息分发。

Handler机制中,我们通过ThreadLocal来保证一个线程中只有一个Looper。


好了,我们最后再来解决一个问题,上面源码中我说过Looper内部维护这一个死循环,那么一定有人有疑问,Looper不会阻塞主线程吗?

我们来揭晓答案吧:

Looper是不会阻塞主线程的,正因为有Looper这个死循环,我们的app才能去即时的相应用户的操作。

不止是我们自己通过代码逻辑发送的Message,包括我们应用中所有的操作,比如开启一个Activity,调用Activity生命周期的方法:onCreate\onResume等,都是通过Handler发送消息,由Looper轮训到来处理的。

因此,Looper不会阻塞我们的主线程。


好了,Handler机制,以及一些常见问题我们一起学习完了,对于一些有经验的开发者理解起来还是很easy的。当然也欢迎大家多提意见。

Now is the funture!


0 0
原创粉丝点击