资讯专栏INFORMATION COLUMN

android源码分析-深入looper handler message

DobbyKim / 2000人阅读

摘要:在这里表示的是不允许退出。这之后会调用到进入实质性的工作函数中。看到了吧,由于函数运行在主线程中,因此以上这些都是在主线程中运行的代码。注意,这个是排他性的,如果前面的可以执行就不会走后面的。现在比较清楚了吧,整个消息循环是如何运转的。

本来是不想写这篇文章的,但是很早以前看过的东西容易遗忘,希望还是给自己一个记录吧,另外此篇希望能够写的深入一些。
looper是什么就不介绍了吧,一个线程的消息泵,handler是消息的操作者,messagequeue是消息队列。
我们从源头开始看起,activity里的主ui线程就是ActivityThread mMainThread。这个ActivityThread的main函数会在程序创建的时候被调用,那么看下内部:

    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("");

        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

首先走了Looper.prepareMainLooper();这个是与普通线程创建looper不同的地方,普通的都是prepare方法调用。那么看看里面:

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

还是prepare,但是传递的参数是false。在这里表示的是不允许退出。再来就是prepare:

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

存储线程本地对象中一个新的looper。同时可以看到,如果已经存在了这个线程本地对象,那么直接报错,也就是说一个线程只允许一个looper存在。
回到ActivityThread的main,初始化好之后就是sMainThreadHandler = thread.getHandler();这个getHandler里直接返回的是mH,其实就是一个Handler的子类H。这个H是个很长的类,就是定义好的对activity默认相应的各项。
这之后会调用到Looper.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;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long traceTag = me.mTraceTag;
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn"t corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycleUnchecked();
        }
    }

首先看到在Looper的构造函数里就创建了MessageQueue:

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

那么这个loop函数中就直接取过来用,后面是个死循环,不断的通过queue.next()获取新的消息,并最终调用msg.target.dispatchMessage(msg);来处理。至此looper分析完了。下面看看Message的msg.target.dispatchMessage(msg);是怎么调用的:
看到message的时候,他的target就是Handler。这下子串上了吧,在looper的loop函数循环中枚举新message,并交给message里的Handler的dispatchMessage函数处理。那么好吧,我们回顾下,在发送message的时候,一般先obtain获取一个消息,我们看看:

    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

看起来像链表是吧,每次取得时候将sPool给m,sPool移动到下一个,然后将sPoolSize减一,最后返回m。再看下回收部分:

    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

这里将自己赋值给sPool,然后sPoolSize++,看到这里应当明白,其实就是个链表的应用,保证sPool指向的是空闲的message的第一个。
然后呢,应用的时候会调用Handler的sendMessage函数,并且将参数设置为刚才获取到的空闲message,对吧。那么我们看看这个sendMessage,最终会调用到sendMessageAtTime中:

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

这里出现了MessageQueue,然后会走到enqueueMessage:

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

第一句就是msg.target = this;,清楚了吧,这里将message的target赋值为handler自身。那么回到loop这个函数中,会走到msg.target.dispatchMessage(msg);这句话,实际上就是在走handler的msg.target.dispatchMessage。再进入到handler中看看这个dispatchMessage:

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

能看到什么?先试图调用message的callback,如果没有则试图调用自身的mCallback的handleMessage,如果还没有,好吧,直接走handleMessage。依次看一下,首先是handleCallback:

    private static void handleCallback(Message message) {
        message.callback.run();
    }

这个callback是个什么呢?可以通过Message的obtain看到:

    public static Message obtain(Handler h, Runnable callback) {
        Message m = obtain();
        m.target = h;
        m.callback = callback;

        return m;
    }

一个runnable,那么这个runnable是何时被赋值的呢?看Handler中:

    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

看到了吧,这里在执行post的时候给的runnable就是这个callback。那么再想想,我们在写代码的时候,很多时候都会走一个handler的post或者postDelayed,执行一段代码在主线程中,这个传递进来的runnable就是message的callback了。顺便说下,View里的post也是调用的这个东西。
下面是Handler自身的mCallback了,在构造Handler的时候可以指定一个callback传递进来,这个Callback是这样定义的:

    public interface Callback {
        public boolean handleMessage(Message msg);
    }

指定的话就会走这个标准的回调,否则最后会走Handler的handleMessage,这个才是我们最常用的继承下来的函数。看到了吧,由于loop函数运行在主线程中,因此以上这些都是在主线程中运行的代码。注意,这3个是排他性的,如果前面的可以执行就不会走后面的。
现在比较清楚了吧,整个消息循环是如何运转的。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/66767.html

相关文章

  • android源码分析-深入消息机制

    摘要:辅助功能类,提供接口向消息池中发送各类消息事件,并且提供响应消息的机制。进入消息泵循环体,以阻塞的方式获取待处理消息。执行消息的派发。并且将返回值保存在了。我们深入下去看看层的部分,在这里明显生成了一个新的,并且将地址作为返回值返回了。 概述 android里的消息机制是非常重要的部分,这次我希望能够系统的剖析这个部分,作为一个总结。首先这里涉及到几个部分,从层次上看,分为java层和...

    superw 评论0 收藏0
  • Android异步消息机制

    摘要:在子线程中发送消息,主线程接受到消息并且处理逻辑。也称之为消息队列,特点是先进先出,底层实现是单链表数据结构得出结论方法初始话了一个对象并关联在一个对象,并且一个线程中只有一个对象,只有一个对象。 目录介绍 1.Handler的常见的使用方式 2.如何在子线程中定义Handler 3.主线程如何自动调用Looper.prepare() 4.Looper.prepare()方法源码分析...

    王晗 评论0 收藏0
  • Android异步消息机制

    摘要:在子线程中发送消息,主线程接受到消息并且处理逻辑。子线程往消息队列发送消息,并且往管道文件写数据,主线程即被唤醒,从管道文件读取数据,主线程被唤醒只是为了读取消息,当消息读取完毕,再次睡眠。 目录介绍 1.Handler的常见的使用方式 2.如何在子线程中定义Handler 3.主线程如何自动调用Looper.prepare() 4.Looper.prepare()方法源码分析 5....

    blair 评论0 收藏0
  • Android之消息机制问题

    摘要:通过向消息池发送各种消息事件通过处理相应的消息事件。消息泵通过不断地从中抽取,按分发机制将消息分发给目标处理者。也称之为消息队列,特点是先进先出,底层实现是单链表数据结构。目录介绍 6.0.0.1 谈谈消息机制Hander作用?有哪些要素?流程是怎样的?简单说一下你的看法! 6.0.0.2 为什么一个线程只有一个Looper、只有一个MessageQueue,可以有多个Handler? 6...

    番茄西红柿 评论0 收藏0

发表评论

0条评论

DobbyKim

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<