Take you in-depth understanding of the Android handler mechanism

Source: Internet
Author: User

Take you in-depth understanding of the Android handler mechanism

Welcome reprint Please indicate source

Speaking of the message mechanism, we will certainly think of handler, because the Android system specifies that the main thread cannot block more than 5s, otherwise "application not responding" will appear. That is, you cannot take time-consuming operations (network requests, database operations, and so on) in the main thread, only in child threads. Let's take a look at what happens when you access the UI in a child thread.

  public void click(View v){    new Thread(new Runnable() {        @Override        public void run() {            mTextView.setText("2");        }    }) .start();}

The result is not an unexpected error:

Android.view.viewrootimpl$calledfromwrongthreadexception:only the original thread that created a view hierarchy can Touc H its Views.

The Checkthread () check in Viewrootimpl is the main thread, if not thrown.

So how can this time be solved in order to update the UI? is actually using handler mechanism!

Handler

First look at how to improve the code, and then analyze the handler mechanism in detail.

   public void click(View v){    new Thread(new Runnable() {        @Override        public void run() {            //拿到Message对象            Message msg = mHandler.obtainMessage();            msg.arg1 = 2;            mHandler.sendMessage(msg);        }    }) .start();}

Then update the UI in Handlemessage

   private Handler mHandler =  new Handler(){    @Override    public void handleMessage(Message msg) {        super.handleMessage(msg);        mTextView.setText(msg.arg1+"");    }};

This will be a success.

Just knowing how to use that is certainly not enough, and we need to know what's behind it.

Let's start with Mhandler.sendmessage (msg). When we call SendMessage, in fact the final call is Sendmessageattime (Msg,long). The source code for this method is as follows:

    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);}

It calls Enqueuemessage () to send the message to MessageQueue. So what is MessageQueue? As the name implies is the message queue, in fact, when we create handler, it needs to be associated with Looper, Looper class has a member variable
MessageQueue Mqueue, it is the message queue. Used to receive handler send message. The MessageQueue is not stored in an array, but instead uses the data structure of the linked list for easy addition and deletion.

Here's a look at the Looper.looper () source code, this method is to give the message to Handler.handlemessage to complete.

   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 this thread is the the local process,//and keep track of what the identity token AC    Tually 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 is in a local variable with case a UI event sets the logger Printer logging = me.mlogging;                    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.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 (i Dent) + "to 0x" + long.tohexstring (newident) + "when dispatching to" + Msg.targe        T.getclass (). GetName () + "" + Msg.callback + "what=" + msg.what);    } msg.recycleunchecked (); }}

3rd, 4 line: Determine whether the Looper object is empty, if it is empty, throw "No Looper;" Looper.prepare () wasn ' t called on the This thread. " Abnormal. In other words, if we create handler in a child thread and call SendMessage (), this exception message is thrown because there is no Looper object. We can convert the current thread to Looper thread through Looper.prepare (). The source code will be analyzed below.

mainly see for (;;) That code, which is a dead loop, constantly executes the next () method, and if there is a new message, give it to Msg.target.dispatchMessage (msg); Here Msg.target is actually handler object. So let's see what Handler.dispatchmessage (msg) has done.

    public void dispatchMessage(Message msg) {    if (msg.callback != null) {        handleCallback(msg);    } else {        if (mCallback != null) {            if (mCallback.handleMessage(msg)) {                return;            }        }        handleMessage(msg);    }}

Actually see here to understand, it calls is Handlemessage (), so we can easily update UI interface!

So what is Mcallback.handlemessage (msg)?

Now let's take a look at this code:

    private Handler mHandler =  new Handler(new Handler.Callback() {    @Override    public boolean handleMessage(Message msg) {        Toast.makeText(getApplicationContext(),"1",Toast.LENGTH_SHORT).show();        return false;    }}){    @Override    public void handleMessage(Message msg) {        Toast.makeText(getApplicationContext(),"2",Toast.LENGTH_SHORT).show();    }};

Note: In line 5th I return false, the results of Toast Show 1, show up and then show 2.
When the return is true, the results of toast only show 1. So we can know that this is actually used to intercept the processing of messages.

Just mentioned Looper.prepare () can convert the current thread to Looper thread. Then take a look at Looper.prepare () source code

    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));}

By throwing that exception we can find that a handler can only have one looper. and a looper internal maintainer MessageQueue, when there is a message looper take the message out of MessageQueue to handler processing. So that they can establish a relationship between them.

Take a look at this line of code in the source Sthreadlocal.set (new Looper (quitallowed)); About threadlocal You can take a look at this article.

http://blog.csdn.net/qq_31609983/article/details/52094032

To think of looper constantly fetching messages from the MessageQueue, it is necessary to call Looper.loop () to continue to fetch the message.

The complete code for sending messages in a child thread is as follows:

    public void click(View v){    final Handler handler =  new Handler();    new Thread(new Runnable() {        @Override        public void run() {            Looper.prepare();            handler.sendMessage();            Looper.loop();        }    }) .start();}

Note Looper.prepare (); Handler.sendmessage (); These two methods cannot be changed in order, so we can take a look at the handler construction method

  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;}

Note that this code mlooper = Looper.mylooper (); If it is empty, throw an exception, the exception means that you must call Looper.prepare (). That is why the order cannot be changed!

Then the reader may ask, we create the handler object in the main thread, and do not call Looper.prepare () also what is the problem ah, it is true, because Activitythread's main () function inside Looper.preparemainlooper (); The Looper object has been created for us automatically. Check the source code:

 public static void prepareMainLooper() {    prepare(false);    synchronized (Looper.class) {        if (sMainLooper != null) {            throw new IllegalStateException("The main Looper has already been prepared.");        }        sMainLooper = myLooper();    }}

Note Smainlooper = Mylooper (); Take a look at the Mylooper () method:

 public static @Nullable Looper myLooper() {    return sThreadLocal.get();}

Speaking so much, it's probably a little dizzy for little white. Ha ha. So next I stole a picture of Hyman teacher to analyze the relationship between Handler,messagequeue,looper ...

0160904160222603)

One day, the boss is meeting with the staff, employees want to go to the toilet, out of politeness, to the boss said I want to the toilet (SendMessage to MessageQueue) The boss thought for a while, replied to "You Go" (Looper.loop), the last employee to WC ( Handlemessage), from the inquiry to the last WC are the employees do, this is the relationship between them ... hahaha.

In fact, there are many ways to send messages handler

    • Msg.sendtotarget ();
    • Mhandler.sendmessageatfrontofqueue ();
    • Mhandler.sendemptymessage ()
    • Mhandler.sendemptymessagedelayed ()
    • Mhandler.post ()
    • Mhandler.postdelayed ()

Although there are many ways, the essence is achieved through Handler.handlemessage ().

There are a few here are not listed here, interested readers can go to the Android official Internet café ...

Statement

Thanks to "Android development art exploration", thanks to the network video, thank Guo Shen.
Let me attach the link, if you are interested, go and see it ...

Video:

http://www.imooc.com/learn/267

Guo Shen Blog:

http://blog.csdn.net/guolin_blog/article/details/9991569

Finally: This is the first time I write an analysis of the source of the article, (it is also the last time ...) hahaha. ), not well written, more messy, but also ask readers to forgive. Written written on the 24 points, is about to usher in a third, I hope that this article for quasi-junior three life to open a good head! I wish you a happy life!

Take you in-depth understanding of the Android handler mechanism

Related Article

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.