Handler、Looper与MessageQueue源码分析

移动开发 Android
在Android中可以通过Handler来更新主线程中UI的变化,更新UI只能在主线程中进行更新,而为了让其他线程也能控制UI的变化,Android提供了一种机制Handler、Looper与MessageQueue一同协作来达到其他线程更新UI的目的。

在Android中可以通过Handler来更新主线程中UI的变化,更新UI只能在主线程中进行更新,而为了让其他线程也能控制UI的变化,Android提供了一种机制Handler、Looper与MessageQueue一同协作来达到其他线程更新UI的目的。

一般我们会在主线程中通过如下方法定义一个Handler

private Handler mHandler = new Handler() { 
        @Override 
        public void handleMessage(Message msg) { 
            tv.setText("mHandler change UI"); 
            super.handleMessage(msg); 
        } 
    };  
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

一般都见不到Looper与MessageQueue的,那么它们都是在哪里调用与如何协作的呢?在主线程不会显式的调用Looper而是会在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("<pre-initialized>"); 
  
        Looper.prepareMainLooper();//创建Looper 
  
        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();//开启Looper循环 
  
        throw new RuntimeException("Main thread loop unexpectedly exited"); 
    }  
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.

如上代码,调用了Looper.prepareMainLooper()方法,在主线程中创建了一个Looper,不信的话我们再查看该方法做了什么

Looper

prepare 

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));//创建Looper并赋给sThreadLocal 
    } 
  
    /** 
     * Initialize the current thread as a looper, marking it as an 
     * application's main looper. The main looper for your application 
     * is created by the Android environment, so you should never need 
     * to call this function yourself.  See also: {@link #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(); 
        } 
    } 
      
    public static @Nullable Looper myLooper() { 
        return sThreadLocal.get(); 
    }  
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.

在prepareMainLooper方法中调用了prepare而通过prepare会发现它其实就是创建了一个Looper,并把它赋给了sThreadLocal。同时可以通过myLooper方法获取当前线程中的Looper。再来看下new Looper(quitAllowed)初始化了什么

private Looper(boolean quitAllowed) { 
        mQueue = new MessageQueue(quitAllowed); 
        mThread = Thread.currentThread(); 
    }  
  • 1.
  • 2.
  • 3.
  • 4.

在这里我们终于看到了MessageQueue了,它创建了一个MessageQueue。该消息队列就是用来保存后续的Message。再回到ActivityThread.main方法中,发现它调用了Looper.loop()是用来开启Looper循环的,监听消息队列MessageQueue中的消息。

loop

我们来看下Looper.loop()的源码:

public static void loop() { 
        final Looper me = myLooper();//获取Looper 
        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.traceBegin(traceTag, msg.target.getTraceName(msg)); 
            } 
            try { 
                msg.target.dispatchMessage(msg);//通过Handler分发消息 
            } 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(); 
        } 
    }  
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.

在loop中首先获取了当前所在线程的Looper,同时也获取到了Looper中的MessageQueue,说明Looper已经与当前的线程进行了绑定。在后面开启了一个for的死循环,发现它做的事件是不断的从消息队列中取出消息,***都交给msg.target调用它的dispatchMessage方法,那么target又是什么呢?我们进入Message

Message

/*package*/ int flags; 
 
    /*package*/ long when
     
    /*package*/ Bundle data; 
     
    /*package*/ Handler target; 
     
    /*package*/ Runnable callback; 
     
    // sometimes we store linked lists of these things 
    /*package*/ Message next 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

发现它就是我们熟悉的Handler,说明***调用的就是Handler中的dispatchMessage方法,对消息的分发处理。这样一来Handler就通过Looper联系上了Looper所绑定的线程,即为主线程。

Handler

public Handler(Callback callback, boolean async) { 
        if (FIND_POTENTIAL_LEAKS) { 
            final Class<? extends Handler> klass = getClass(); 
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && 
                    (klass.getModifiers() & Modifier.STATIC) == 0) { 
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " + 
                    klass.getCanonicalName()); 
            } 
        } 
  
        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; 
    }  
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

通过Handler的初始化,它获取了它所处线程的Looper,同时也获取了Looper中的消息队列。当然如果所处线程的Looper为空的话就会抛出异常,这就解释了为什么在非主线程中创建Handler要分别调用Looper.prepare与Looper.loop而主线程则不需要,因为它默认已经调用了。

dispatchMessage

public void dispatchMessage(Message msg) { 
        if (msg.callback != null) { 
            handleCallback(msg); 
        } else { 
            if (mCallback != null) { 
                if (mCallback.handleMessage(msg)) { 
                    return
                } 
            } 
            handleMessage(msg); 
        } 
    } 
private static void handleCallback(Message message) { 
        message.callback.run(); 
    }     
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

回到前面,对于dispatchMessage的处理,首先判断msg.callback是否为空,这里callback通过上面的Message应该能知道他就是一个Runnable,如果不为空则直接调用Runnable的run方法。否则调用Handler的handleMessage方法.而这个方法相信大家已经很熟悉了,对事件的处理都是在这个方法中执行的。因为通过前面我们已经知道了Handler已经联系上了主线程,所以handleMessage中的处理自然相对于在主线程中进行,自然也能更新UI了。通过这里我们能把Looper比作是一个桥梁,来连接Looper所在的线程与Handler之间的通信,同时管理消息队列MessageQueue中的消息。那么前面的Runnable又是如何不为空的呢?我们使用Handler有两种方法,一种是直接创建一个Handler并且重写它的handleMessage方法,而另一种可以通过Handler.post(Runnable)来使用,这样事件的处理自然就在run方法中实现。

上面介绍了Handler是如何联系上了需要操作的线程与对消息是如何取出与处理的。下面来谈谈消息是如何放入到Looper中的MessageQueue中的。

sendMessageAtTime

通过Handler发送消息的方式很多,例如:sendMessage、sendEmptyMessage与sendMessageDelayed等,其实到***他们调用的都是sendMessageAtTime方法。所以还是来看下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); 
    }  
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

而sendMessageAtTime则就是调用了enqueueMessage操作,看这方法名就知道是入队列操作了。

enqueueMessage

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { 
        msg.target = this; 
        if (mAsynchronous) { 
            msg.setAsynchronous(true); 
        } 
        return queue.enqueueMessage(msg, uptimeMillis); 
    }  
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

果不其然直接调用了MessageQueue中的queue.enqueueMessage(msg, uptimeMillis)将消息加入消息队列,同时这段代码msg.target = this 将当前的Handler赋给了msg.target,这就是前面所说的Looper.loop方法中调用的Handler。这样就把消息放到了MessageQueue中,进而通过前面所讲的loop来取出消息进行相应的处理,这样就构成了整个对消息进行处理的系统。这也是使用Handler内部所发生的原理。好了Handler、Looper与MessageQueue它们之间的联系基本就是这些了。我也简单画了张图希望有所帮助

总结

来总结下它们之间的流程。首先创建Handler而在Handler所处的线程中必须要有一个Looper,如果在主线程中默认帮我们实现了,其他线程必须调用Looper.prepare来创建Looper同时调用Looper.loop开启对消息的处理。每个Looper中都有一个MessageQueue它是用来存储Message的,Handler通过post或者send..等一系列操作通过Looper将消息放入到消息队列中,而Looper通过开启一个***的循环来一直监听着消息的处理,不断从MessageQueue中取出消息,并交给与当前Looper所绑定的handler的dispatchMessage进行分发,***根据情况调用Runnable的run或者Handler的HandlerMessage方法对消息进行***的处理。

其它分享:https://idisfkj.github.io/arc...

责任编辑:庞桂玉 来源: segmentfault
相关推荐

2011-11-23 09:33:45

HandlerLooperMessage

2014-05-22 15:07:44

Android消息处理机制Looper

2014-05-22 15:41:59

Android消息处理机制Looper

2014-05-22 15:48:50

Android消息处理机制Looper

2014-05-22 15:04:00

Android消息处理机制Looper

2014-05-22 15:00:16

Android消息处理机制Looper

2014-05-22 15:38:27

Android消息处理机制Looper

2014-05-22 14:57:28

Android消息处理机制Looper

2014-05-22 15:15:53

Android消息处理机制Looper

2014-05-22 15:18:25

Android消息处理机制Looper

2014-05-22 15:33:31

Android消息处理机制Looper

2014-05-22 15:45:58

Android消息处理机制Looper

2013-04-11 12:40:16

Android消息机制

2021-08-12 16:28:10

AndroidHandleLooper

2021-09-08 10:47:33

Flink执行流程

2016-11-29 09:38:06

Flume架构核心组件

2016-11-25 13:26:50

Flume架构源码

2022-08-15 11:28:22

handler注册过程APiServer

2016-11-25 13:14:50

Flume架构源码

2009-12-22 13:36:39

Linux Sysfs
点赞
收藏

51CTO技术栈公众号