An explanation of the Android handler message processing mechanism

Source: Internet
Author: User

Objectivewe've been dealing with handler almost every day since we started learning Android. With it, we've handled the time-consuming operation in the child thread, and can use it to update the UI. It provides great convenience for our communication between threads, And today's blog to give a detailed introduction of handler's message loop mechanism, step by step to understand the mystery, this article does not introduce the detailed use of handler, explore the internal principle. So look at this blog's children's shoes need to have handler basic use Abilitythis blog based on the Android 6.0 source code explainedfirst throw a simple example of use
public class Demoact extends Appcompatactivity {    private Handler h = new Handler () {        @Override public        void Han Dlemessage (Message msg) {            toast.maketext (Demoact.this, "received", Toast.length_long). Show ();        }    ;    @Override    protected void onCreate (Bundle savedinstancestate) {        super.oncreate (savedinstancestate);        Setcontentview (R.layout.act_demo);    }    /**     * button click event     *     * @param view *     /public    void ClickView (view view) {        new Thread () {            @ Override public            Void Run () {                h.sendemptymessage (0);            }        }. Start ();    }}


:
we can see a simple use, then the implementation of the principle of what is it?let's Explore together!
to make a diagram in the main thread, drawing the approximate processMessageQueue and Looperthe introductionin Android, a thread can correspond to a Looper object, cannot have multiple, why say can, looper as a message of the circulator, in a thread can use it also can not use it, so a thread can have a Looper object cannot have more than one.when it comes to the news circulator, you have to rip off the so-called message queue MessageQueue. Each Looper object maintains a message queue MessageQueue, which is used to hold messages (message), MessageQueue, the stored messages are executed according to the FIFO (first in and out) principle
introduction of Handlerhandler How to send a messagehandler is a class where we send messages and process messages, so how do we send messages in the above diagram?
    Public Final Boolean sendemptymessage (int.)    {        return sendemptymessagedelayed (what, 0);    }
above is the source of sending an empty message, you can see the call to another method, then click to enter ~ ~ ~
    Public final Boolean sendemptymessagedelayed (int what, long Delaymillis) {        Message msg = Message.obtain ();        Msg.what = what;        Return sendmessagedelayed (msg, delaymillis);    }
Here we can clearly see, when we send a message, how to send is not one message object, but an empty message, then it will automatically create a message object for us, after all, in fact, the final send is definitely a message objectgo on , go.
    Public Final Boolean sendmessagedelayed (Message msg, long Delaymillis)    {        if (Delaymillis < 0) {            Delaymillis = 0;        }        Return Sendmessageattime (MSG, systemclock.uptimemillis () + Delaymillis);    }
in this method, the delay time of the millisecond value is judged, because the time will never flow backwards ~ ~ ~keep going.
    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);    }

in this method, a member variable is empty, but not thrown, but the exception is printed, then what is this member variable ?Actually, he's the handler. The message queue in the looper of the thread! Hey, didn't you say that the message queue is in Looper? Why is there a copy in handler? look at the handler's constructor to know!
    Public Handler (Callback Callback, Boolean async) {        if (find_potential_leaks) {            final class<? extends handler& Gt 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 = callback;        masynchronous = async;    }

from the constructor we can see that we get the Looper object of the current thread from the Looper, and then take out the message queue from inside, so this explains the problem of the member variable aboveSo, the way to go .
    Private Boolean enqueuemessage (MessageQueue queue, Message msg, long Uptimemillis) {        msg.target = this;        if (masynchronous) {            msg.setasynchronous (true);        }        Return Queue.enqueuemessage (msg, uptimemillis);    }

At this point, the message is finally sent to the message queue, which describes how handler sends the message.
handler how the message is handledAs we can see in the flowchart above, who did the message? It's looper, yes, that's it, so we're going to go see Looper's code.the Looper.loop method is the key method:
 /** * Run The message queue in this thread.     Be sure to call * {@link #quit ()} to end of the 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 the the the the The local process,//and keep track of what the identity toke        n actually is.        Binder.clearcallingidentity ();        Final Long ident = Binder.clearcallingidentity (); for (;;) {Message msg = Queue.next ();//might block if (msg = = NULL) {//No Message Indicat                ES the message queue is quitting.            Return }//This must is in a local variable, in case a UI event sets the logger Printer logging = Me.mlogg            ing if (logging! = null) {LOGGING.PRINTLN (">>>>> dispatching to" + Msg.target + "+ msg.callback +": "+ msg.what);            } msg.target.dispatchMessage (msg); if (logging! = null) {logging.println ("<<<<< finished to" + Msg.target + "" + Msg.callbac            k);             }//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.tohex                        String (ident) + "to 0x" + long.tohexstring (newident) + "when dispatching to"            + Msg.target.getClass (). GetName () + "" + Msg.callback + "what=" + msg.what);        } msg.recycleunchecked (); }    }

From the annotation of this method, we can see the function of this method:That is, this method opens a dead loop to come up with each message, and after it is taken out, it is distributed through the DispatchMessage (Message msg) method of the target object in the Message object (which is actually a reference to the handler that sent the message) (processing ) message, post the code for Distribution (processing):
    /**     * Handle system messages here.     */Public    void DispatchMessage (Message msg) {        if (msg.callback! = null) {            handlecallback (msg);        } else {            if (mcallback! = null) {                if (Mcallback.handlemessage (msg)) {                    return;                }            }            Handlemessage (msg);        }    }

The code is simple, judging by the two callback (explained later), is null to call Handlemessage (msg), this method is the most common way we use handler, the above example code is to rewrite this method, Can look back to see ~ ~
What is the callback in handler?in the handler source code, there is an interface as follows:
    /**     * Callback interface You can use when instantiating a Handler to avoid * have to implement your own     subclass of Handler.     *     * @param msg A {@link android.os.Message Message} object     * @return True If no further handling is desired     *    /public interface Callback {public        boolean handlemessage (Message msg);    
There is a paragraph in the Message object:
so the above mentioned in the distribution (processing) of the message when the Mcallback is actually an interface, the interface method is also handlemessage.There is also a message object in the callback, this is a runnable interfaceNote: Although this is a runnable interface, but do not look at this is a thread often used in the interface, you think it can handle the time-consuming operation, here is not allowed, otherwise it will block the main threadSo when you create handler, you can do whatever you like:1. Using the callback interface in handler
    Private Handler H = new Handler (new Handler.callback () {        @Override public        boolean handlemessage (Message msg) {
   return false;        }    });
The return value here is whether the control message continues to be passed to the Handlemessage method in handler execution
    public void DispatchMessage (Message msg) {        if (msg.callback! = null) {            handlecallback (msg);        } else {            if ( Mcallback! = null) {                if (Mcallback.handlemessage (msg)) {                    return;                }            }            Handlemessage (msg);        }    }
From the distribution (processing) of the message, you can see that if true is returned, then the Handlemessge method in handler will not be executed.
2. Using the callback in the Message object
Message m = Message.obtain (H, new Runnable () {<span style= "white-space:pre" ></span> @Override <span Style = "White-space:pre" ></span>public Void Run () {<span style= "white-space:pre" ></span>//do something, This run method is the main thread called the <span style= "White-space:pre" ></SPAN>}); H.sendmessage (m);


This is the process of handler processing messages, do you have a certain understanding of handler's sending and processing messages?
Some of the questions you should be asking aboutmessage Circulator, I did not open, that is, does not call Looper.loop in the main thread, why the main thread of the message loop is useful ?Here 's the answer:
    public static void Main (string[] args) {Trace.tracebegin (Trace.trace_tag_activity_manager, "Activitythreadmain        ");        Samplingprofilerintegration.start ();  Closeguard defaults to True and can is quite spammy. We//Disable it here, but selectively enable it later (via/strictmode) on debug builds, but using DROPBO        x, not logs.        Closeguard.setenabled (FALSE);        Environment.initforcurrentuser ();        Set The reporter for event logging in Libcore eventlogger.setreporter (New Eventloggingreporter ());        Androidkeystoreprovider.install (); Make sure Trustedcertificatestore looks in the right place for CA certificates final File Configdir = environmen        T.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, "Activit        Ythread "));        }//End of event Activitythreadmain.        Trace.traceend (Trace.trace_tag_activity_manager);        Looper.loop ();    throw new RuntimeException ("Main thread loop unexpectedly exited"); }

This is the main method in the Activitythread class, and you can see that it helps us initialize the LooperThe corresponding code is: Looper.preparemainlooper ()the message circulator is turned onThe corresponding code is: Looper.loop ();
create multiple handler to process messages, why can they be separated without disturbingat the time of sending the message, there is this paragraph:
    Private Boolean enqueuemessage (MessageQueue queue, Message msg, long Uptimemillis) {        msg.target = this;        if (masynchronous) {            msg.setasynchronous (true);        }        Return Queue.enqueuemessage (msg, uptimemillis);    }
It is clear that the target of the message object is the handler of the message , so when the message is processed, the original handler is found based on the target, and then it is processed
Looper.loop () is a dead loop, why is not the card dead
I use the red box to get the next message from the message queue, followed by a comment that this method may block, so it will be blocked when there is no messageSome people may still have questions:then I did not send a message, an app did not send any handler messages, then why the app is still normal to walk, and no card deadA : You do not send a message, does not mean that the system does not send a message, in Android using a large number of handler message mechanism

An explanation of the Android handler message processing mechanism

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.