Get the App
SLTechnology News&Howtos  ›  Development  › 

How to analyze the source code of Handler, Looper and MessageQueue

Shulou Source: shulou.com Published: 2022-06-02 02:55:10 10月03日 Update

This article shows you how to carry out Handler, Looper and MessageQueue source code analysis, the content is concise and easy to understand, absolutely can make your eyes bright, through the detailed introduction of this article, I hope you can get something.

In Android, the change of UI in the main thread can be updated through Handler, and the update of UI can only be updated in the main thread. In order to let other threads control the change of UI, Android provides a mechanism for Handler, Looper and MessageQueue to work together to achieve the purpose of updating UI.

In general, we define a Handler in the main thread as follows

Private Handler mHandler = new Handler () {@ Override public void handleMessage (Message msg) {tv.setText ("mHandler change UI"); super.handleMessage (msg);}}

You generally don't see Looper and MessageQueue, so where are they invoked and how do they work together? Looper is not explicitly called in the main thread but is called by default in the ActivityThread.main method.

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 () / / create 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 (); / / enable Looper loop throw new RuntimeException ("Main thread loop unexpectedly exited");}

As in the code above, the Looper.prepareMainLooper () method is called, and a Looper is created in the main thread. If you don't believe me, we'll see what the method does.

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)) / / create a Looper and assign it to 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 ();}

You call prepare in the prepareMainLooper method and through prepare you will find that it actually creates a Looper and assigns it to sThreadLocal. At the same time, you can get the Looper in the current thread through the myLooper method. Let's take a look at what new Looper (quitAllowed) initializes.

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

Here we finally see MessageQueue, which creates a MessageQueue. The message queue is used to hold the subsequent Message. Back in the ActivityThread.main method, you find that it calls Looper.loop () to open the Looper loop and listen for messages in the message queue MessageQueue.

Loop

Let's look at the source code of Looper.loop ():

Public static void loop () {final Looper me = myLooper (); / / get Looper if (me = = null) {throw new RuntimeException ("No Looper; Looper.prepare () wasn't called on this thread.");} final MessageQueue queue = me.mQueue / / get message queue / / 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 ina 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) / / distribute messages via Handler} finally {if (traceTag! = 0) {Trace.traceEnd (traceTag);}} if (logging! = null) {logging.println ("

Tags: Threads methods messages that is processing queues at the same time updates contacts source code events can be passed naturally looped analyzed between code content again Apple Docker Huawei Linux macOS MariaDB Microsoft MySQL NVidia OPPO Reno Linux Huawei Shulou Technology NVidia Redmi