Handler asynchronous message processing mechanism, from source code view

Source: Internet
Author: User

Reprint Annotated Source: http://blog.csdn.net/xiaohanluo/article/details/51994401
Jiang Answer: HTTP://WWW.JIANSHU.COM/P/E72ABA99012A

Brief introduction

In Android development often encounter the situation of asynchronous message processing, in particular, the network request after successful or failed to update the UI, but the update UI can only be in the UI thread, or error, this time need to notify the UI thread to update the UI, so handler appeared.

Use of Handler

The use of handler is very simple and looks directly at examples.

    Private Static Final intKey_request_success =0x01;PrivateHandler Mhandler =NewHandler () {@Override         Public void Handlemessage(Message msg) {//Here is on the UI thread            if(Msg.what = = key_request_success) {//Change UI}        }    }; ... ...//Some other operations    Private void Changeui() {Message message = Mhandler.obtainmessage ();        Message.what = key_request_success;    Mhandler.sendmessage (message); }

A handler member variable Mhandler is declared, the method is replicated, and handleMessage(Message msg) a message is sent using Mhandler, which is eventually called to the handleMessage method and then the UI update operation.

Seeing such an easy-to-use asynchronous message processing method will certainly look at how the internal implementation of the message is dispatched.

Handler internal information dispatch message into queue

All messages are sendMessage sent out using methods (and other similar methods) and are viewed from the sendMessage beginning.

     Public Final Boolean SendMessage(Message msg) {returnSendmessagedelayed (MSG,0); }    ... Public Final Boolean sendmessagedelayed(Message msg,LongDelaymillis) {if(Delaymillis <0) {Delaymillis =0; }returnSendmessageattime (MSG, systemclock.uptimemillis () + Delaymillis); }    ... Public Boolean Sendmessageattime(Message msg,LongUptimemillis) {MessageQueue queue = Mqueue;if(Queue = =NULL) {//Exception handling}returnEnqueuemessage (Queue, MSG, uptimemillis); }    ...Private Boolean Enqueuemessage(MessageQueue queue, Message msg,LongUptimemillis) {Msg.target = This;if(masynchronous) {msg.setasynchronous (true); }returnQueue.enqueuemessage (msg, uptimemillis); }

We can see that the handler sends the message to the method eventually, and sendMessageAtTime in this way it does one thing and puts the message in a message queue. Remember msg.target this assignment, and then we'll look at what we did when we put it in the queue.

    BooleanEnqueuemessage (Message msg,LongWhen) {//Exception handling        synchronized( This) {//Exception handlingMsg.markinuse ();            Msg.when = when; Message p = mmessages;BooleanNeedwake;if(p = =NULL|| when = =0|| When < P.when) {//New head, Wake up the event queue if blocked.Msg.next = p;                Mmessages = msg;            Needwake = mblocked; }Else{needwake = mblocked && P.target = =NULL&& msg.isasynchronous (); Message prev; for(;;)                    {prev = p; p = p.next;if(p = =NULL|| When < P.when) { Break; }if(Needwake && p.isasynchronous ()) {Needwake =false;                }} Msg.next = P;            Prev.next = msg; }if(Needwake)            {Nativewake (mptr); }        }return true; }

It's clear from the code that you can see.

    • If the new message joins the queue for the first time, or if the new message latency is less than the queue's first message delay time, the new message is placed in the queue header.
    • If the queue is not empty, the new message delay time is not the shortest, and the new message is inserted to a location in the queue.

In summary, after the new message is inserted into the queue, Message Queuing is an ordered queue that is sorted by the delay time, the shorter the delay, the closer the queue header. In this way, it is possible to guess that the system takes the messages in the queue one at a time and then distributes the processing.

Message Dispatch distribution

We all know that. The message was added to an ordered queue in the order of delay, and the message was added to the queue and there was a place to process it, so we looked at where the queue was handled.
First, let's look at where the member variables of the handler MessageQueue are initialized or assigned, starting from the source and searching for clues.

 public  handler  () {this  (null ,    Span class= "Hljs-keyword" >false );    }    ... public  handler  (Callback Callback, boolean  async)        {... mlooper = Looper.mylooper (); if  (Mlooper = = null )                {throw  new  runtimeexception (         "Can ' t create handler inside thread that have not called looper.prepare ()" );        } mqueue = Mlooper.mqueue;        Mcallback = callback;    masynchronous = async; }

The original is directly with Looper assignment, that will not be the processing of this message queue in Lopper it? Hurry and see. Looper the code is not much, soon see loop() this method.

     Public Static void Loop() {FinalLooper me = Mylooper ();//Exception handling         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 loggerPrinter 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 LongNewident = 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 (); }    }

That's right here!! loop()there is a loop in the method that takes the message out of the message queue and then distributes the work. We pay attention to this line of code msg.target.dispatchMessage(msg) , called a msg.tartget method of distributing messages, remember when the above message into the message queue, the attention of msg.target the assignment operation? msg.targetis actually the handler!!! we send the message Check out the message distribution and processing process.

Message processing

Go directly to the method in handler dispatchMessage(msg) and find this method relatively simple.

    publicvoiddispatchMessage(Message msg) {        ifnull) {            handleCallback(msg);        else {            ifnull) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }

It is easy to understand that if both the message and handler CallBack member variables are empty, the method of calling handler itself is a method of making a copy handlerMessage(Message msg) of the handler when we instantiate it, and the concrete processing of the final message comes back to our hands.

Scheduling diagram


Handler sends a message message, messages enter the message queue, Looper constantly takes the message out of the messages queue, and then hands over the handler processing, processing the code to the user. This allows us to send a message in a non-UI thread, but the final processing goes back to the UI thread for some UI action.

Other usage

Although handler is used to process asynchronous messages, it has a delayed function, so handler can also do a timed task processor, such as AD end countdown and so on handler.

Tips

Although handler seems to be easy to use, if you are careful, you will find that this set of mechanisms is very strict with the management of the message. When a message is removed from the message queue or after the message is processed, it is not simply discarded, but the method of the message itself is invoked recycleUnchecked() .

    voidRecycleunchecked () {//Mark the message as in and the It remains in the recycled object pool.        //Clear out all other details.Flags = Flag_in_use; what =0; Arg1 =0; Arg2 =0; obj =NULL; ReplyTo =NULL; Sendinguid =-1; when =0; target =NULL; callback =NULL; data =NULL;synchronized(Spoolsync) {if(Spoolsize < Max_pool_size)                {next = SPool; SPool = This;            spoolsize++; }        }    }

First, some member variables in the message inside the reset operation, we found this property in the last side MAX_POOL_SIZE !! This means that there is an upper limit to the number of message in this set of mechanisms. Cautious will find that if you instantiate one with new using the message every time, there will always be a point at which the number of message exceeds the maximum limit.
So when we get the message, we must use a Handler.obtainMessage() method or Message.obtain(Handler h) method.

If you use new to instantiate a message, there is a hole in it, careful.

Q&a

The loop () method of the Looper class stops looping after processing the queue, and if a new message is added, how is the system called to Looper Loop ()?

After the information is added to the message queue, nativeWake(mPtr) This line of code is run as nativeWake() a local method, which is used to invoke the method at the bottom of the system Looper.loop() .

A deferred task message was sent by handler, and this message has not been processed yet, how is it withdrawn?

There are five ways to recall messages handler.

    • Removecallbacks (Runnable R)
    • Removecallbacks (Runnable r, Object object)
    • removemessages (int what)
    • Removemessages (int what, Object object)
    • Removecallbacksandmessages (Object object)

But the message was actually deleted in the MessageQueue queue, and MessageQueue provides three ways to delete the message

    • Removemessages (Handler h, int what, Object object)
    • Removemessages (Handler H, Runnable r, Object object)
    • Removecallbackandmessage (Handle H, Runnable r, Object object)

Parameters are member variables in message (the handler parameter is passed in handler call MessageQueue Delete Message method, which is the handler itself), and the message is removed from the message queue when the passed-in parameter is equal to the property in message. The argument object is a supplemental condition, the object is passed in null, the preceding conditions are met, the object is not empty, and all the conditions need to be met.

    voidRemovecallbacksandmessages (Handler H, Object object) {if(H = =NULL) {return; }synchronized( This) {Message p = mmessages;//Remove all messages at front.             while(P! =NULL&& P.target = = h && (object = =NULL||                P.obj = = object) {Message n = p.next;                Mmessages = n;                P.recycleunchecked ();            p = n; }//Remove all messages after front.             while(P! =NULL) {Message n = p.next;if(n! =NULL) {if(N.target = = h && (object = =NULL||                        N.obj = = object) {Message nn = n.next;                        N.recycleunchecked (); P.next = nn;Continue;            }} p = N; }        }    }

It is easy to see from the code that if an removeCallbacksAndMessage object is passed in as null when the MessageQueue method is called, all messages in the message queue will be emptied. So when this mHandler.removeCallbacksAndMessage(null) is called, all the information in the message queue is emptied.

Waiting to be perfected ...

Handler asynchronous message processing mechanism, from source code view

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.