Android source code Analysis--handler and Looper mechanism detailed

Source: Internet
Author: User

Applications in the Android system, like Java applications, are message-driven, simply put: There is a message queue, we can constantly add messages to this message queue, and remove the message from it, processing the message. The main work related to this job in Android is done by Handler,looper and message.

    • Looper class: A message loop is run for a thread, there is a message queue inside, and each thread only allows a maximum of one looper;
    • Handler class: Allows you to send messages to a thread's message queue and process messages;
    • Message class: Messaging class.
Using the sample

First, we learn how to use, Looper, and handler through a simple example, and study how it works through this example;
1. We prepare for the message loop in Looperthread and create a handler to process the message, noting that handler is created after calling Looper.prepare ();

 Public  class looperthread extends Thread {     PublicHandler Mhandler;@Override     Public void Run() {//TODO auto-generated method stubLooper.prepare ();synchronized( This) {Mhandler =NewHandler () {@Override                 Public void Handlemessage(Message msg) {//TODO auto-generated method stub                    Super. Handlemessage (msg); LOG.W ("Looperthread","Handlemessage::thread ID---"+ getId ());        }            };        } looper.loop ();    Notifyall (); }}

2. Next we create a new thread in the main thread and send a message to the Looperthread thread through handler in Looperthread;

    FinalLooperthread Mlooperthread =NewLooperthread (); Mlooperthread.start ();NewThread () {@Override         Public void Run() {//TODO auto-generated method stub             while(Mlooperthread.mhandler = =NULL) {Try{Wait ();//Prevent handler from being created when sending messages}Catch(Interruptedexception e) {//TODO auto-generated catch blockE.printstacktrace (); }} mLooperThread.mHandler.sendEmptyMessage (0); LOG.W (TAG,"Send message::thread ID---"+ getId ()); }}.start ();

This example essentially creates a new thread and sends a message to looperthread in that thread. In order to prevent the handler from being established while sending the message, a synchronization is made, and when Mhandler is null, the thread is blocked to wait for the thread to wake up when the handler is established. You can see the results in log:

Looper analysis

From the above example we can see that if we want to do message management in this thread, we first need to call the Looper.prepare method, so let's first look at this method:

 public   Static  void  prepare  () {Prepare (true ); } private  static   void  prepare  (Boolean quitallowed) {if  (ST Hreadlocal. get  ()! = null ) {throw  new  runtimeexception (" only one Looper could be created per thread "); } sthreadlocal. set     (new  Looper (quitallowed)); }

You can see that in the Prepare method, you first determine whether Looper has been created in the thread, and then call the set method of Threadlocal. Threadlocal is a thread-local variable class in Java that allows each thread to maintain its own independent object, typically through Threadlocal.set () to an object in the thread that the thread uses itself, and other threads that do not need access or access. For the threadlocal mechanism here do not do too much to repeat.

Here we set a looper for the thread, and then we look at the Looper constructor:

    privateLooper(boolean quitAllowed) {        new MessageQueue(quitAllowed);        mThread = Thread.currentThread();    }

As you can see, in the constructor method, we create a new message queue and set up the current thread.

Next we create a handler, about handler we will analyze, in the end we call the Looper loop method for the message loop. Let's take a look at this method:

     Public Static void Loop() {the//mylooper () method is to return the looper we just set by Sthreadlocal.get ()        FinalLooper me = Mylooper ();if(Me = =NULL) {Throw NewRuntimeException ("No Looper; Looper.prepare () wasn ' t called on the This thread. "); }FinalMessageQueue queue = Me.mqueue;//Ensure that the thread is consistent with the local process and that the identity token is loggedBinder.clearcallingidentity ();Final LongIdent = Binder.clearcallingidentity (); for(;;) {Message msg = Queue.next ();//May be blocked            if(msg = =NULL) {//No message indicates that the message queue has exited.                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); }//Distribute the messageMsg.target.dispatchMessage (msg);if(Logging! =NULL) {Logging.println ("<<<<< finished to"+ Msg.target +" "+ Msg.callback); }//Ensure that the thread does not crash during distribution            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.recycle (); }    }

As you can see, the loop method is primarily to remove messages from the message queue and distribute the message.

To summarize, Looper's work:

    • Encapsulates a message queue,
    • Use prepare to associate Looper with the thread that calls the Prepare method
    • Distributing messages using the Loop function
Handler Analysis

Knowing the work of Looper, let's see how to send the message out. First, let's look at how it's constructed,

    publicHandlerasync) {        ......        mLooper = Looper.myLooper();        ifnull) {            thrownew RuntimeException(                "Can‘t create handler inside thread that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;        mCallback = callback;        async;    }

The parameterless construction method calls the This (null, flase) construction method, and you can see that there is a looper in the member variable of handler, first obtaining the looper of the thread that is currently creating handler, In addition, you can see that a message queue is also saved in handler that eventually points to the Looper message queue.

When we call the SendMessage method and send a message to Looper, let's take a look at this method, how the message is passed. The SendMessage method is eventually called to the Sendmessageattime method to:

     Public Boolean Sendmessageattime(Message msg,LongUptimemillis) {MessageQueue queue = Mqueue;if(Queue = =NULL) {RuntimeException E =NewRuntimeException ( This+"Sendmessageattime () called with no Mqueue"); LOG.W ("Looper", E.getmessage (), E);return false; }returnEnqueuemessage (Queue, MSG, uptimemillis); }Private Boolean Enqueuemessage(MessageQueue queue, Message msg,LongUptimemillis) {Msg.target = This;if(masynchronous) {msg.setasynchronous (true); }returnQueue.enqueuemessage (msg, uptimemillis); }

As you can see, the SendMessage method eventually calls the Queue.enqueuemessage method to join the message queue in Looper.

In the above we see that our distribution message is called by the DispatchMessage method:

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

As you can see, DispatchMessage sets a priority mechanism for message handling:

    1. If the message comes with callback, it is handed to the callback processing of the message;
    2. If the handler set up the callback, then to handler callback processing;
    3. If both are not, call the Handlemessage method to process.
Synchronization issues for Handler and Looper

In the example above, we can see that handler and Looper are synchronous problems, and if handler is not created in Looperthread, a message is sent in the second thread, which throws a null pointer exception. In the above, I refer to the Android Handlerthread, using the wait/notifyall approach to solve the problem, in practice we can use the Handlerthread to complete.

    FinalHandlerthread Mhandlerthread =NewHandlerthread ("Looperthread"); Mhandlerthread.start ();FinalHandler Mhandler =NewHandler (Mhandlerthread.getlooper ()) {@Override         Public void Handlemessage(Message msg) {//TODO auto-generated method stub            Super. Handlemessage (msg); LOG.W ("Looperthread","Handlemessage::thread ID---"+ Mhandlerthread.getid ()); }    };NewThread () {@Override         Public void Run() {//TODO auto-generated method stubMhandler.sendemptymessage (0); LOG.W (TAG,"Send message::thread ID---"+ getId ()); }}.start ();

We can look at the source code of Handlerthread:

    @Override     Public void Run() {Mtid = Process.mytid (); Looper.prepare ();synchronized( This) {Mlooper = Looper.mylooper ();        Notifyall ();        } process.setthreadpriority (mpriority);        Onlooperprepared ();        Looper.loop (); Mtid =-1; } PublicLooperGetlooper() {if(!isalive ()) {return NULL; }//If The thread has been started, wait until the Looper have been created.        synchronized( This) { while(IsAlive () && Mlooper = =NULL) {Try{Wait (); }Catch(Interruptedexception e) {                }            }        }returnMlooper; }

As you can see, this idea is consistent with what we have just shown in the example.

Android source code Analysis--handler and Looper mechanism detailed

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.