Handler+looper+messagequeue in-depth explanation

Source: Internet
Author: User

Overview : Android uses messaging mechanisms to communicate between threads, threads create their own message loops through Looper, MessageQueue is a FIFO message queue, Looper is responsible for extracting messages from MessageQueue. and distributes to the message specifies the target handler object. The handler object binds to the thread's local variable looper, encapsulating the interface that sends the message and processes the message.

Example : Before we introduce the principle, let's introduce an example of the Android thread communication, which is to send the message "Hello" to another thread named "Customthread" from the main thread after the click button.

Looperthreadactivity.java

Package Com.zhuozhuo;

Import android.app.Activity;
Import Android.os.Bundle;
Import Android.os.Handler;
Import Android.os.Looper;
Import Android.os.Message;
Import Android.util.Log;
Import Android.view.View;
Import Android.view.View.OnClickListener;

public class Looperthreadactivity extends activity{


Private final int msg_hello = 0;
Private Handler Mhandler;

@Override
public void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
Setcontentview (R.layout.main);
New Customthread (). Start ();//new and start Customthread instance

Findviewbyid (R.ID.SEND_BTN). Setonclicklistener (New Onclicklistener () {

@Override
public void OnClick (View v) {///click on interface to send message
String str = "Hello";
LOG.D ("Test", "Mainthread is ready to send msg:" + str);
Mhandler.obtainmessage (Msg_hello, str). Sendtotarget ();//Send message to Customthread instance

}
});

}





Class Customthread extends Thread {
@Override
public void Run () {
Steps to establish a message loop
Looper.prepare ();//1, initializing Looper
Mhandler = new Handler () {//2, Looper object bound Handler to Customthread instance
public void Handlemessage (message msg) {//3, defining methods for handling messages
Switch (msg.what) {
Case Msg_hello:
LOG.D ("Test", "Customthread receive msg:" + (String) msg.obj);
}
}
};
Looper.loop ();//4, start message loop
}
}
}

Main.xml

<?xml version= "1.0″encoding=" utf-8″?>
<linearlayout xmlns:android= "Http://schemas.android.com/apk/res/android"
android:orientation= "Vertical"
Android:layout_width= "Fill_parent"
android:layout_height= "Fill_parent"
>
<textview
Android:layout_width= "Fill_parent"
android:layout_height= "Wrap_content"
android:text= "@string/hello"
/>
<button android:text= "Send Message" android:id= "@+id/send_btn" android:layout_width= "Wrap_content" Android:layout_ height= "Wrap_content" ></Button>
</LinearLayout>

Principle:

We see that there are four steps to establishing a message loop for a thread:

1. Initialize Looper

2. Binding handler to Customthread instance Looper object

3. Define methods for handling messages

4. Start the message loop

Let's take this example as a clue and dive into the Android source code to show how the Android framework builds the message loop and distributes the message.

1. Initialize Looper:Looper.prepare ()

Looper.java

private static final ThreadLocal sthreadlocal = new ThreadLocal ();
public static final void prepare () {
if (sthreadlocal.get () = null) {
throw new RuntimeException ("Only one Looper could be created per thread");
}
Sthreadlocal.set (New Looper ());
}

When a thread calls Looper's static method prepare (), the thread creates a new Looper object and puts it into the thread's local variables, which are not shared with other threads (about threadlocal). Let's take a look at the constructor of Looper ():

Looper.java

Final MessageQueue Mqueue;
Private Looper () {
Mqueue = new MessageQueue ();
Mrun = true;
Mthread = Thread.CurrentThread ();
}

You can see that in the constructor of Looper, a Message Queuing object Mqueue is created, and Looper is called at this time. The thread of the prepare () establishes a message loop object (the message loop has not yet started).

2. Binding Handler to Customthread instance Looper object: mhandler= new Handler ()

Handler.java

Final MessageQueue Mqueue;
Final Looper Mlooper;
Public Handler () {
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 have not called looper.prepare ()");
}
Mqueue = Mlooper.mqueue;
Mcallback = null;
}

Handler through Mlooper = Looper.mylooper (); The local variable bound to the thread Looper up, and handler through Mqueue =mlooper.mqueue; Gets the thread's message queue. At this point, handler is bound to the message queue of the thread that created the handler object.

3. Define a method for handling messages: Override public void Handlemessage (Message msg) {}

Subclasses need to override this method to implement the processing method after receiving the message.

4. Start message loop: Looper.loop ()

All preparations are ready, and it's time to start the message loop! The Looper static method loop () implements the message loop.

Looper.java

public static final void loop () {
Looper me = Mylooper ();
MessageQueue queue = Me.mqueue;

Make sure the identity of the the the the The local process,
And keep track of the What, identity token actually is.
Binder.clearcallingidentity ();
Final Long ident = Binder.clearcallingidentity ();

while (true) {
Message msg = Queue.next (); Might block
if (!me.mrun) {
Break
//}
if (msg! = null) {
if (Msg.target = = null) {
No Target is a magic identifier for the quit message.
Return
}
if (me.mlogging!= null) me.mLogging.println (
">>>>> dispatching to" + Msg.target + ""
+ Msg.callback + ":" + msg.what
);
Msg.target.dispatchMessage (msg);
if (me.mlogging!= null) me.mLogging.println (
"<<<<< finished to" + Msg.target + ""
+ Msg.callback);

Make sure that during the course of dispatching the
The identity of the thread wasn ' t corrupted.
Final Long newident = Binder.clearcallingidentity ();
if (ident! = newident) {
LOG.WTF ("Looper", "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 ();
}
}
}

while (true) represents the "loop" in the message loop, Looper calls Queue.next () in the loop body to get the next message in the message queue that needs to be processed. When msg! = is null and msg.target! = is null, call Msg.target.dispatchMessage (msg); Distribute the message when the distribution is complete, call Msg.recycle (), and recycle the message.

Msg.target is a handler object that represents the handler object that needs to process the message. The handler void DispatchMessage (Message msg) method is as follows:

Handler.java

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

Visible when msg.callback== null and mcallback = = NULL, this example is made up of handlemessage (msg); processing the message, above we say that the subclass overrides this method can implement the message of the specific processing process.

Summary : From the above analysis process, the core of the message loop is that Looper,looper holds the message Queue MessageQueue object, a thread can set Looper as the local variable of the thread, which is equivalent to the thread set up a corresponding message queue. Handler's role is to encapsulate the process of sending and processing messages, so that other threads can send messages to the thread that created the handler only if they need to manipulate handler.

Handler+looper+messagequeue in-depth explanation

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.