Wirelessly message loop mechanism handler and Looper detailed

Source: Internet
Author: User

We know that wirelessly's UI thread is not thread-safe, we can't take time out in the UI thread, and it's usually our practice to turn on a sub-thread to handle time-consuming operations in a child thread, but Android does not allow UI updates to be performed on child threads, and usually we do that with the handler mechanism. , that is, when the time-consuming operation in the child thread completes, the message is sent to the main thread in the child thread through handler, and the received message is processed in the handler Handlemessage method in the main thread. This is the message mechanism of wirelessly, the message mechanism in Android mainly refers to the operation mechanism of handler, but the handler operation requires the support of the underlying MessageQueue and looper mechanisms.

Here we explain the wirelessly of the message loop mechanism, that is, the handler,messagequeue,looper mechanism. Note This blog belongs to the advanced content of Android, so some basic things if crossing do not understand the situation please Baidu to solve.

First, let's look at a standard example of code that uses the handler mechanism:

Class Looperthread extends Thread {public      Handler Mhandler;      public void Run () {          looper.prepare ();          Mhandler = new Handler () {public              void Handlemessage (Message msg) {                   //handle messages here              }          };          Looper.loop ();      }  }



This code is certainly not unfamiliar to everyone, because this is the use of the handler mechanism in Android, one of the most standard code demonstration, perhaps crossing may say that I use the handler when I did not use Looper.prepare () and Looper.loop ()

statement, at that time because we used handler usually in the UI thread, and the UI thread has already done that for us by default, as we'll talk about later. The reason why we chose to create handler in a sub-thread is because it gives us a clearer understanding of the relationship between the Handler,messagequeue,looper in the Android message loop, because many of the details in the main thread are hidden.

First, from this code you can see that there are two concepts involved (in fact, the message loop mechanism in Android involves three important concepts), here is a brief introduction

Looper: A message loop that is used to remove messages from the MessageQueue message queue for processing.

Handler: Message sending and processing, Handler sending a message through SendMessage to message queue MessageQueue, handling messages through Handlermessage

MessageQueue: Message Queuing, which holds messages sent by handler, is used only to hold messages


First explain the whole process of the message loop in Android, and then explain it in detail from the above code.

The wirelessly message loop is implemented using the Looper class, and Looper is thread-based, that is, a Looper object is associated with the line threads that created it when using Looper.prepare () Statement, it creates a Looper object and a MessageQueue object, and then, when the handler is created, gets the Looper object to the thread where the handler is located (if the parameterless constructor is called) . This Looper object is also available for its MessageQueue object , because it is equivalent to handler associated with Looper. this way, the messages sent through handler know which looper should be processed. This is the understanding of the entire Android message loop mechanism core , namely Meaagequeue and looper associated, handler and looper associated, from here also can see Looper is the core of the Android message loop mechanism.


Here is an example of the above model code for a detailed explanation.

First we look at the Looper.prepare () statement, that is, look at the source of prepare:

public static final void prepare () {    if (sthreadlocal.get () = null) {        throw new RuntimeException ("Only one Looper May is created per thread ");    }    Sthreadlocal.set (New Looper ());}
From here you can see that the prepare () function does two things: Create a Looper object and then add it to sthreadlocal by Sthreadlocal.set (New Looper ()); Here you have to mention an important concept in the Android message loop mechanism: ThreadLocal, because this involves the implementation of the Looper object's associated functionality with the line threads. Threadlocal its role is that the value obtained by threadlocal is different when accessing the same Threadlocal object in various threads, that is, the value stored in threadlocal is thread-based. Let's take a look at the set method of threadlocal:

public void Set (T value) {        Thread CurrentThread = Thread.CurrentThread ();        Values values = VALUES (CurrentThread);        if (values = = null) {            values = initializevalues (CurrentThread);        }        Values.put (this, value);    }

You can see that the set function gets the current thread first, and then produces a Valuse object through the current thread, and then uses the put method of values to associate value (that is, the Looper object) with this (that is, the Threadlocal object). Through this code we should know that Looper is thread-related, because the Set method produces Valuse objects through the thread, and then saves the Looper by valuse the object put method.


Next we look at Handler Handler=new handler (); This statement, let's look at handler () this parameterless constructor.

Public Handler () {    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 have not called Loope R.prepare () ");    }    Mqueue = Mlooper.mqueue;    Mcallback = null;}
From here we can see that looper.mylooper () is called first, and the method is to return the Looper associated with the current thread, and you can see that if the obtained mlooper is NULL, an exception is thrown. This also shows that the creation of the handler before creating the handler object, obtained Looper object, we can get to Looper associated with the MessageQueue object, that is Mqueue = Mlooper.mqueue; The Message Queuing MessageQueue is created as described earlier when creating Looper. This code focuses on Looper.mylooper (), which, through this function, obtains the Looper object associated with the current line threads, which is why the message sent by the handler object knows it should be handled by that Looper. Let's take a look at the code:

public static Looper Mylooper () {        return sthreadlocal.get ();    }
You can see that he is using the Sthreadlocal.get () method to get the Looper object, which is relative to the set method we described above threadlocal, one for storing data and one for extracting data.

Let's take a look at the Sthreadlocal.get () method:

Public T get () {        //-Optimized for the fast path.        Thread CurrentThread = Thread.CurrentThread ();        Values values = VALUES (CurrentThread);        if (values! = null) {            object[] table = values.table;            int index = hash & values.mask;            if (this.reference = = Table[index]) {                return (T) Table[index + 1];            }        } else {            values = Initializevalues (c Urrentthread);        }        Return (T) Values.getaftermiss (this);    }
You can see that the Sthreadlocal.get () method gets the current thread, constructs a values object through the current thread, and then returns its stored data through Valuse (which is, of course, the Looper object). It is also because the Looper object that is obtained in handler is the same object as the Looper object that we create in the current thread, which is the key to ensure that the information sent by the handler object is handled correctly by Looper.


Finally, take a look at Looper.loop (); statement, the function of this statement is to open the Looper loop, we look at its source code:

public    static final void loop () {Looper me = Mylooper ();    MessageQueue queue = Me.mqueue; while (true) {Message msg = Queue.next ();//might block if (msg! = null) {if (Msg.target = = Nu            ll) {return; } if (me.mlogging!= null) me.mLogging.println (">>>>> dispatching to" + MSG.)            Target + "" + Msg.callback + ":" + msg.what);            Msg.target.dispatchMessage (msg);                    if (me.mlogging!= null) me.mLogging.println ("<<<<< finished to" + Msg.target + ""            + Msg.callback);        Msg.recycle (); }    }}
You can see that the loop method first gets the current Looper object, then gets the MessageQueue object of the Looper object, and then passes through Queue.next () continuously in a while loop, removing a message from the message queue. DispatchMessage (msg) is then called by the message Msg.target this property to dispatch the message, Msg.target This property essentially sends a message to the MessageQueue handler object, which is to pass the message sent by handler to its dispatchmessage (msg); This switches the code logic to the thread that created the handler to execute.

Let's take a look at Handler's DispatchMessage (msg);

public void DispatchMessage (Message msg) {    if (msg.callback! = null) {        handlecallback (msg);    } else {        if ( Mcallback! = null) {            if (Mcallback.handlemessage (msg)) {                return;            }        }        Handlemessage (msg);}    }
You can see that Handlemessage (msg) is called in the method, and this is the callback method that we handle the message in handler.

Finally, we use the SendMessage to send messages, Handler provides a number of functions to send messages, and eventually call the Sendmessageattime () method, we look at its source:

public boolean sendmessageattime (Message msg, long Uptimemillis) {    Boolean sent = false;    MessageQueue queue = Mqueue;    if (queue! = null) {        msg.target = this;        Sent = Queue.enqueuemessage (msg, uptimemillis);    }    else {        RuntimeException e = new RuntimeException (this            + "sendmessageattime () called with no Mqueue");        LOG.W ("Looper", E.getmessage (), E);    }    return sent;}
You can see that the MessageQueue enqueuemessage (MSG, uptimemillis) is finally called in the method, as the name implies, its role is to queue a message, its source code is not important, All we need to know is that it is done by inserting a message into a one-way list to complete the enqueue operation.


In the front we said in the main thread we do not need to create a looper, this is because these work Android has helped us to do, the main thread in Android is Activitythread, the main thread of the entry function is main, we look at its source code:

public static void Main (string[] args) {    samplingprofilerintegration.start ();    Closeguard.setenabled (false);    Environment.initforcurrentuser ();    Eventlogger.setreporter (New Eventloggingreporter ());    Process.setargv0 ("<pre-initialized>");    Looper.preparemainlooper ();    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 ();    throw new RuntimeException ("Main thread loop unexpectedly exited");}
You can see that the Looper.preparemainlooper () method is called in the method, and the Looper.preparemainlooper () method calls the Looper.prepare () method. So in the main thread we don't need to create a Looper object ourselves.


Well, through the above explanation believe crossing to wirelessly's message mechanism has been very clear, the following summary:

The 1Looper object is the core of the Android message loop, and the Looper object is thread-based, and when we create a Looper object We associate the Looper we created with the thread it is on by Threadlocal object, specifically through Sthreadlocal.set (New Looper ()); The statement saves it, and in addition to creating a Looper object, it automatically creates a message queue MessageQueue object for us.

The role of 2Looper is to continuously check the message queue MessageQueue for message messages through a while loop, and if present, pass Msg.target.dispatchMessage (msg); The message is handed to the handler object that sent the message for processing.

3 When we create a handler object, the interior first obtains the Looper object associated with the current thread, that is, the call to Looper.mylooper (), and, specifically, by the Sthreadlocal.get () method,

This ensures that the Looper object obtained in handler is the same object as the Looper object we created in the current thread, thus guaranteeing that the information sent by the handler object is handled correctly looper.

4 In addition, when a handler object is created, it is internally acquired by the Looper object to obtain the MessageQueue object associated with the Looper object, so that messages sent through SendMessage are sent to the MessageQueue object. This is also the key to ensure that the information sent by the handler object is handled by the correct MessageQueue (which is essentially done by the MessageQueue, since the creation of this is done within Looper, That is, MessageQueue is associated with Looper).

5MessageQueue is only used to save the message, the dispatch of the message is done through Looper, and in the loop loop of Looper, a while loop is continuously viewed to see if there is a message in message queue MessageQueue. If there is a msg.target.dispatchMessage (msg), the message is passed to the handler object that sent the message for processing, so that the logic of the code is switched to the thread where the handler is located.


The diagram shows the following:


Ok above is I understand about the Android message loop mechanism of all content, crossing if feel good please point a praise Oh, also please crossing support my other blog article.

Wirelessly message loop mechanism handler and Looper detailed

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.