安卓源码学习之Handler执行流程

来源:互联网 发布:python中数据清洗的库 编辑:程序博客网 时间:2024/05/22 13:16

学安卓也有一段时间了,一直都是做项目或者看别人的博客,自己从来没有写一片像样的文章来记录自己所学到的知识,现在发现如果把所学到得知识记录下来对知识也是一种温习,并且会掌握得更加牢固。


今天记录我所掌握的Handler消息机制执行流程,平时我们都会使用到Handler对象来进行延迟消息的处理或者结合线程来更新UI控件,但是对里面的原理也不是很了解,所以我今天看了一下源码,把看到的东西记录下来。
首先我们使用Handler肯定的new一个它的对象,那new的过程当中它都做了些什么事呢?于是乎我打开了源码:

//这里是它的午餐构造方法,它总共有几个构造方法,最终都是调用的这个构造//方法下面的构造方法public Handler() {        this(null, false);    }    //最终调用的是这个构造方法public Handler(Callback callback, boolean async) {        ...        mLooper = Looper.myLooper();//这里可以看到获取了Looper对象        if (mLooper == null) {        //如果looper对象为空,则抛出异常,这里先给出一点疑问,就是,为甚        //么Looper.myLooper()方法可能会为空呢            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;//获取消息队列        mCallback = callback;        mAsynchronous = async;    }

当然,获取到Handler对象以后肯定是要使用它的,我们通过调用它的sendMessage(msg)方法或者其他sendXXX方法来发送消息,于是乎我们得有一个消息对象啊,我们可以这么做:
Message msg=new Message()或者Message msg=handler.obtainMessage();大家都知道下面这个方法效率更加高,这是为什么呢请看源码:

public final Message obtainMessage(){    return Message.obtain(this);}//最终handler.obtinMessage()会调用Message对象的这个方法:public static Message obtain() {        synchronized (sPoolSync) {            if (sPool != null) {                Message m = sPool;                sPool = m.next;                m.next = null;                sPoolSize--;                return m;            }        }        return new Message();}//从上面可以看到,如果使用obtinMessage()方法会先往消息池里面取出,如果去不到则实例化一个返回,这就是为什么obtinMessage比newMessage效率高的原因!

好了,获取到Message对象以后肯定得发送消息啊,于是我们跟踪一下handler.sendMessage(Message msg)方法源码:

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) {    MessageQueue queue = mQueue;     ...     //可以看到这里会对消息进行排序    return enqueueMessage(queue, msg, uptimeMillis); }

可以看到发送消息最终会调用enqueueMessage(queue, msg, uptimeMillis)方法,我们进入这个方法一看究竟:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;        ...        //这里调用了MessageQueue的enqueueMessage方法        return queue.enqueueMessage(msg, uptimeMillis);}根据MessageQueue的enqueueMessage方法:boolean enqueueMessage(Message msg, long when) {        ...        synchronized (this) {            ...            msg.when = when;            Message p = mMessages;            boolean needWake;            //这里判断是否发送消息的延迟时间when 是否为0,如果不是0的话            //则将其加入到队列的前面            if (p == null || when == 0 || when < p.when) {                // New head, wake up the event queue if blocked.                msg.next = p;                mMessages = msg;                needWake = mBlocked;            } else {                needWake = mBlocked && p.target == null && msg.isAsynchronous();                Message prev;                for (;;) {                    prev = p;                    p = p.next;                    if (p == null || when < p.when) {                        break;                    }                    if (needWake && p.isAsynchronous()) {                        needWake = false;                    }                }                msg.next = p; // invariant: p == prev.next                prev.next = msg;            }            // We can assume mPtr != 0 because mQuitting is false.            if (needWake) {                nativeWake(mPtr);            }        }        return true;    }    //从上面的代码可以分析出如果出入的延迟时间为0则优先级最高//这里是从消息队列中取出消息以后底层调用的方法,好像从这里以后这个方法是系//底层调用的,查了一下资料貌似是一个linux管道设置的方法 public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            //这里调用了handleMessage方法            handleMessage(msg);        }    }

//于是调用了发送消息以后就会调用handlerMessage(Message msg)方法进行我们自己的代码处理了。
具体的流程图可以用如下图来表示:

引入上面我提出的问题,就是在Handler的无参构造方法里:

public Handler(Callback callback, boolean async) {        ...        mLooper = Looper.myLooper();//这里可以看到获取了Looper对象        if (mLooper == null) {        //如果looper对象为空,则抛出异常,这里先给出一点疑问,就是,为甚        //么Looper.myLooper()方法可能会为空呢            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;//获取消息队列        mCallback = callback;        mAsynchronous = async;    }

我提出的为什么Looper.myLooper();可能获取的Looper对象为空?首先想一下我们有时候在子线程中创建Handler对象的时候会发生什么情况呢?当然是报错了,这个报错的信息就是上面源码中的提示信息:”Can’t create handler inside thread that has not called Looper.prepare()”,那为什么主线程中new 一个Handler对象就不会报错呢?那是因为在主线程创建的时候系统就会跟着创建一个Looper对象,而子线程中不会主动创建Looper对象,当我们在子线程中先这样写:

Looper.prepare();....Looper.loop();

就不会报错了,这里贴出主线程创建Looper对象的源码:

 public static void main(String[] args) {        ...        Looper.prepareMainLooper();//创建主线程的Looper对象        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }        AsyncTask.init();        if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }        Looper.loop();//循环取出消息

所以我们在主线程中new Handler不会报错,在子线程中需要加上Looper.prepare()和Looper.loop()方法的原因了。

具体的流程就分析完毕,如果不对的地方麻烦看的朋友指出一下,我写博客是为了把自己学习的东西记录下来,同时锻炼一下自己的表达能力,希望如果有不对的地方麻烦老师指点一下,谢谢!

0 0
原创粉丝点击