美文网首页UIT
Handler源码浅析(二)

Handler源码浅析(二)

作者: siyanGo | 来源:发表于2017-02-07 16:02 被阅读24次

    Looper 大管家

    • Handler(消息发送者和接受者)
    • Looper(消息循环)
    • Message(消息)
    • MessageQueue(消息队列)

    先看Looper源码里给的Demo

    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这个类是为线程消息循环工作的,
    • 线程默认是没有Looper的 需要用prepare方法创建,然后调用loop方法进行工作直到线程停止。
    • 大多数与Handler进行交互
    • Class used to run a message loop for a thread. Threads by default do
    • not have a message loop associated with them; to create one, call
    • {@link #prepare} in the thread that is to run the loop, and then
    • {@link #loop} to have it process messages until the loop is stopped.
    • <p>Most interaction with a message loop is through the
    • {@link Handler} class.

    从Looper的创建可以看出:

    • Looper是一个单例, 每个线程只能创建一个Looper
    • 初始化Looper 的时候初始化一个MessageQueue 并且与当前线程绑定
    
       public static void prepare() {
            prepare(true);
        }
    
        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));
        }
    
        private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            mThread = Thread.currentThread();
        }
    

    当你初始化一个Looper它并不能工作,你需要调用Looper.loop();
    先获取自己的looper和消息队列
    注意里面的for(;;){...

    //在死循环里不断重复接收消息队列里的消息
    ** Message msg = queue.next(); //可能阻塞 **

    还记得Handler里的 ** msg.target = this; **
    在那里我们的target 得到发送Message的Handler
    现在我们在调用dispatchMessage(msg);
    ** msg.target.dispatchMessage(msg); **
    Handler里的疑惑解决了 Looper绑定Handler-> Handler 发送消息->Looper启动消息队列->获取消息调用Handler的分发消息方法->获得消息处理 这应该就是工作流程

    msg.recycleUnchecked(); 发送完的消息会回收

    }

    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 {
              //派发消息给Handler
                    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();
            }
        }
    
    

    到这里就有个问题主线程(UI 线程)是如何处理事件,更新UI的,我也没构建Looper啊
    我们去看看ActivityThread的代码

    在如此复杂的代码中找到了main函数。其中果然有
    ** Looper.prepareMainLooper(); 和 ** Looper.loop();

     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("<pre-initialized>");
    
            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");
        }
    

    Handler总结

    相关文章

      网友评论

        本文标题:Handler源码浅析(二)

        本文链接:https://www.haomeiwen.com/subject/zaapittx.html