In the Android asynchronous processing one: using Thread+handler to implement non-UI thread update UI interface, we talked about using Thread+handler to implement the interface update, in fact, the non-UI thread sends the message to the UI thread, notifies the UI thread to update the interface. , this article will learn more about the implementation of communication between Android threads.
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.
Code download
Looperthreadactivity.java
PackageCom.zhuozhuo;Importandroid.app.Activity;ImportAndroid.os.Bundle;ImportAndroid.os.Handler;ImportAndroid.os.Looper;ImportAndroid.os.Message;ImportAndroid.util.Log;ImportAndroid.view.View;ImportAndroid.view.View.OnClickListener; Public classLooperthreadactivityextendsactivity{/**Called when the activity is first created.*/ Private Final intMsg_hello = 0; PrivateHandler Mhandler; @Override Public voidonCreate (Bundle savedinstancestate) {Super. OnCreate (savedinstancestate); Setcontentview (R.layout.main); NewCustomthread (). Start ();//To Create and start a Customthread instanceFindviewbyid (R.ID.SEND_BTN). Setonclicklistener (NewOnclicklistener () {@Override Public voidOnClick (View v) {//send a message when you click the interfaceString str = "Hello"; LOG.D ("Test", "Mainthread is ready to send msg:" +str); Mhandler.obtainmessage (Msg_hello, str). Sendtotarget ();//sending a message to a Customthread instance } }); } classCustomthreadextendsThread {@Override Public voidrun () {//steps to establish a message loopLooper.prepare ();//1. Initialize LooperMhandler =NewHandler () {//2. Binding handler to Customthread instance Looper object Public voidHandlemessage (Message msg) {//3. Define methods for handling messages Switch(msg.what) { CaseMSG_HELLO:LOG.D ("Test", "Customthread receive msg:" +(String) msg.obj); } } }; Looper.loop ();//4. Start the 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>
Log Print Results:
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" 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 () { new MessageQueue (); true ; = 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
FinalMessageQueue Mqueue;FinalLooper Mlooper; PublicHandler () {if(find_potential_leaks) {Finalclass<?extendsHandler> 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 NewRuntimeException ("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 voidLoop () {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 LongIdent =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 LongNewident =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 (). GE Tname () + "" + 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.c Allback! = null else { if (mcallback! = null ) { if re Turn ; }} 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. Thus, in the previous article, "Android asynchronous processing one: using Thread+handler to implement a non-UI thread update UI interface," the UI thread creates a message loop when it is created (public static final in Activitythread void Main (string[] args), so we can send messages to the UI thread's handler in other threads, to update the UI.
This blog address: http://blog.csdn.net/mylzc/article/details/6771331 reprint please indicate the source
Android asynchronous processing three: Handler+looper+messagequeue in-depth explanation