Explain the implementation principle of handler in Android _android

Source: Internet
Author: User
Tags message queue prepare

In Android, only the main thread can manipulate the UI, but the main thread cannot take time-consuming operations, or it blocks threads and generates ANR exceptions, so it often puts time-consuming operations on other child threads. If you need to update the UI in a child thread, you typically send a message via Handler, and the main thread accepts the message and makes the appropriate logical processing. In addition to using Handler directly, you can update the UI using the Post method of the View and the Runonuithread method of the activity, which also utilizes the Handler inside. In the previous article, the Android Asynctask source analysis also mentioned that the internal use of Handler to transfer the processing results of the task back to the UI thread.

This paper deeply analyzes the message processing mechanism of Android and understands the working principle of Handler.

Handler
take a look at the use of Handler first.

 public class Mainactivity extends Appcompatactivity {private static final int Message_
 
 Text_view = 0;
 Private TextView Mtextview;
    Private Handler Mhandler = new Handler () {@Override public void Handlemessage (msg) {switch (msg.what) {
    Case MESSAGE_TEXT_VIEW:mTextView.setText ("UI successfully updated");
   Default:super.handleMessage (msg);

 }
  }
 };
  @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
  Setcontentview (R.layout.activity_main);
  Toolbar Toolbar = (Toolbar) Findviewbyid (R.id.toolbar);

  Setsupportactionbar (toolbar);

  Mtextview = (TextView) Findviewbyid (R.id.text_view);
    New Thread (New Runnable () {@Override public void run () {try {thread.sleep (3000);
    catch (Interruptedexception e) {e.printstacktrace ();
   } mhandler.obtainmessage (Message_text_view). Sendtotarget ();

 }). Start (); }
}

The code above first creates an instance of handler, and overrides the Handlemessage method, in which the corresponding UI update is based on the type of message received. So take a look at the source code of the handler construction method:

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:" +
    Klass.getcanonicalname ());
  }

 Mlooper = Looper.mylooper ();
 if (Mlooper = = null) {
  throw new RuntimeException (
   "Can" t create handler inside thread that is has not called Loope R.prepare () ");
 }
 Mqueue = Mlooper.mqueue;
 Mcallback = callback;
 masynchronous = async;
}

In the constructor method, the Looper object is obtained by calling Looper.mylooper (). If Mlooper is empty, an exception is thrown: "Can" t create handler inside thread that has not called looper.prepare () "means that you cannot invoke Looper.prepare ( Creates a handler for the thread. The example above does not call this method, but it does not throw an exception. In fact, because the main thread has been invoked by us at startup, we can create Handler directly. If it is on another child thread, creating the Handler directly can cause the application to crash.

After getting Handler, it gets its internal variable mqueue, which is the MessageQueue object, the message queue, that holds the message sent by Handler.

By this point, all three important roles of the Android messaging mechanism have emerged, Handler, Looper, and MessageQueue. Generally in the code we contact more is Handler, but Looper and MessageQueue is Handler operation is indispensable.

Looper
the previous section analyzes the construction of Handler, which calls the Looper.mylooper () method, and the following is its source code:

Static final threadlocal<looper> sthreadlocal = new threadlocal<looper> ();

public static @Nullable Looper Mylooper () {return
 sthreadlocal.get ();
}

The code for this method is simple: Get the Looper object from the sthreadlocal. Sthreadlocal is a ThreadLocal object, which indicates that Looper is thread independent.

In the Handler construct, from the thrown exception, each thread wants to obtain looper needs to invoke the prepare () method to continue looking at its code:

private static void Prepare (Boolean quitallowed) {
 if (sthreadlocal.get ()!= null) {
  throw new RuntimeException (" Only one looper could created per thread ");
 }
 Sthreadlocal.set (New Looper (quitallowed));
}

It is also very simple to set a looper for sthreadlocal. It should be noted, however, that if the sthreadlocal has already been set, an exception will be thrown, meaning that a thread will have only one looper. When you create a looper, a message queue is created internally:

Private Looper (Boolean quitallowed) {
 mqueue = new MessageQueue (quitallowed);
 Mthread = Thread.CurrentThread ();
}

The question now is, Looper looks very important, what does it do?
Answer: Looper Open the message circulatory system, constantly from the message queue MessageQueue remove messages to Handler processing.

Why do you say that, look at the loop method of Looper:

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 local process,//and keep track of what that identity token ACTU
 Ally is.
 Binder.clearcallingidentity ();
 
 Final Long ident = Binder.clearcallingidentity (); Infinite loop for (;;) {Message msg = Queue.next ();//might blocks if (msg = null) {//No message indicates the ' message ' queue is Q
   Uitting.
  Return
  }//This must is in a local variable, in 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 (Ident) + "to 0x" + Long.tohex
  String (newident) + "while dispatching to" + Msg.target.getClass (). GetName () + "" + Msg.callback + "what=" + msg.what);
 } msg.recycleunchecked ();

 }
}

The code for this method is a bit long, not to investigate the details, only to see the overall logic. As you can see, there is a dead loop inside this method, which gets the next message through the MessageQueue next () method without getting blocked. If a new message is successfully fetched, the Msg.target.dispatchMessage (msg) is invoked, Msg.target is the Handler object (as seen in the next section), and DispatchMessage is the distribution message (which is already running on the UI thread). The following analysis of the message delivery and processing process.

Message Sending and processing
when a child thread sends a message, it invokes a series of SendMessage, Sendmessagedelayed, and Sendmessageattime methods, and eventually calls Sendmessageattime (msg , long Uptimemillis), the code is as follows:

public boolean sendmessageattime (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);

Private Boolean enqueuemessage (MessageQueue queue, MSG, long Uptimemillis) {
 msg.target = this;
 if (masynchronous) {
  msg.setasynchronous (true);
 }
 Return Queue.enqueuemessage (msg, uptimemillis);


This method is to invoke Enqueuemessage to insert a message in the message queue, and in the Enqueuemessage total, Msg.target will be set to the current Handler object.

When a message is inserted into a message queue, Looper is responsible for taking it out of the queue and then invoking the Handler DispatchMessage method. Next look at how this approach handles messages:

public void DispatchMessage (message msg) {
 if (msg.callback!= null) {
  handlecallback (msg);
 } else {
  if ( Mcallback!= null) {
   if (Mcallback.handlemessage (msg)) {return
    ;
   }
  }
  Handlemessage (msg);
 }

First, if the message's callback is not empty, the handlecallback processing is invoked. Otherwise, the mcallback of the Handler is judged to be empty and not NULL to invoke its Handlemessage method. If it is still empty, the handlemessage of Handler itself is invoked, which is the method that we rewrite when we create the Handler.

If the Handler post (Runnable R) method is invoked when a message is sent, the Runnable is encapsulated into the callback of the Message object, and then the sendmessagedelayed is invoked, with the following code:

Public Final Boolean post (Runnable R)
{return
 sendmessagedelayed (Getpostmessage (R), 0);
}
private static Message Getpostmessage (Runnable r) {message
 m = Message.obtain ();
 M.callback = R;
 return m;
}

The handlecallback is called for processing at this time in DispatchMessage:

 private static void Handlecallback (Message message) {
 message.callback.run ();
}

You can see that the Run method is invoked directly to process the message.

If you provide a Callback object directly when you create the handler, the message is processed by the Handlemessage method of the object. Callback is an interface within the Handler:

Public interface Callback {public
 boolean handlemessage (msg);
}

The above is the process of sending and processing messages, which are sent on a child thread, but when processing the DispatchMessage method runs on the main thread.

Summarize
So far, the rationale behind the Android message processing mechanism is over. As you can now see, message handling is done through Handler, Looper, and MessageQueue. Handler is responsible for sending and processing messages, looper creating message queues and constantly fetching messages from queues to Handler, MessageQueue for saving messages.

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.