Original address: Http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html#!comments
As a junior preparatory programmer, one of my great pleasures in learning Android is that I can learn the design ideas of Google Daniel through the source code. Android source contains a large number of design patterns, in addition, the Android SDK also carefully designed for us a variety of helper classes, for me as eager as the level of the people who want to be advanced, it is worth reading. This is not, a few days ago in order to understand the Android message processing mechanism, I saw looper,handler,message these several classes of source code, the results were once again by the Googler design shock, special share with you.
Android's message processing has three core classes: Looper,handler and message. There's actually a message queue, but MQ is encapsulated in Looper, and we don't deal directly with MQ, so I don't use it as a core class. Here are the following:
Thread of the magician Looper
Looper literally means "circulator", which is designed to make a normal thread into a looper thread . The so-called Looper thread is the thread that loops work. In program development (especially in GUI development), we often need a thread to loop continuously, and once a new task is executed, the execution continues to wait for the next task, which is the looper thread. Creating a Looper thread with the Looper class is simple:
public class Looperthread extends Thread {
@Override
public void Run () {
Initializes the current thread to a looper thread
Looper.prepare ();
// ... Other processing, such as instantiation of handler
Start loop processing of Message Queuing
Looper.loop ();
}
}
With the above two lines of core code, your thread will be upgraded to Looper thread!!! Isn't it amazing? Let's slow down and see what each of these two lines of code does.
1) Looper.prepare ()
As you can see, you now have a Looper object in your thread that internally maintains a message queue MQ. Note that a thread can have only one Looper object , and for what? Let's look at the source code.
public class Looper {
The Looper object in each thread is actually a threadlocal, the thread local storage (TLS) object
private static final ThreadLocal sthreadlocal = new ThreadLocal ();
Message Queuing within the Looper
Final MessageQueue Mqueue;
Current thread
Thread Mthread;
。。。 Other properties
Each Looper object has its message queue, and the thread it belongs to
Private Looper () {
Mqueue = new MessageQueue ();
Mrun = true;
Mthread = Thread.CurrentThread ();
}
We call this method to create a Looper object in the calling thread's TLS
public static final void prepare () {
if (sthreadlocal.get () = null) {
Attempting to create looper again in a thread that has looper will throw an exception
throw new RuntimeException ("Only one Looper could be created per thread");
}
Sthreadlocal.set (New Looper ());
}
Other methods
}
Through the source code, prepare () the work behind the way at a glance, its core is to define the Looper object as threadlocal. If you are not sure what threadlocal is, please refer to "Understanding Threadlocal".
2) Looper.loop ()
When the loop method is called, the Looper thread begins to actually work, and it continuously executes the message (also called the task) that pulls the team header from its own MQ. The source code analysis is as follows:
View Code
In addition to the prepare () and loop () methods, the Looper class provides some useful methods, such as
Looper.mylooper () Gets the current thread Looper object:
public static final Looper Mylooper () {
Calling Looper.mylooper () on any thread will return the looper of that thread.
Return (Looper) sthreadlocal.get ();
}
GetThread () Gets the thread that the Looper object belongs to:
View Code
The Quit () method ends the Looper loop:
View Code
So far, you should have a basic understanding of looper and summarize some of the points:
1. Each thread has and can have at most one Looper object, which is a threadlocal
2.Looper has a message queue inside, the loop () method call after the thread begins to continuously remove the message from the queue execution
3.Looper causes a thread to become a looper thread.
So how do we add a message to MQ? Here's handler!. (Applause ~ ~ ~)
Asynchronous Processing Master Handler
What is handler? Handler plays the role of adding messages and processing messages to MQ (handling only messages sent by itself), notifying MQ that it is going to perform a task (sendMessage) and performing the task (Handlemessage) at loop to its own. The entire process is asynchronous . Handler is created with a looper associated with it, the default constructor associates the looper of the current thread, but this can be set. The default construction method:
public class Handler {
Final MessageQueue Mqueue; The associated MQ
Final Looper Mlooper; The associated Looper
Final Callback Mcallback;
Other properties
Public Handler () {
Did not read, directly skipped,,,
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 ());
}
}
The default is to associate the looper of the current thread
Mlooper = Looper.mylooper ();
Looper cannot be null, that is, the default construction method can only be used in Looper threads
if (Mlooper = = null) {
throw New RuntimeException (
"Can ' t create handler inside thread that have not called looper.prepare ()");
}
Important!!! The associated Looper MQ is directly used as its own MQ, so its messages are sent to the MQ of the associated Looper
Mqueue = Mlooper.mqueue;
Mcallback = null;
}
Other methods
}
Here we can add handler to the previous Looperthread class:
View Code
After adding handler, the effect is as follows:
As you can see, a thread can have multiple handler, but only one looper!
Handler sending messages
With handler, we can use,,, post(Runnable)
, postAtTime(Runnable, long)
postDelayed(Runnable, long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message, long)
and sendMessageDelayed(Message, long)
These methods to send messages to MQ. Look at these APIs you may feel that handler can send two kinds of messages, one is Runnable object, one is a message object, this is a visual understanding, but in fact, the post runnable object is encapsulated into a message object, see source code:
This method is used to send the Runnable object to the associated MQ, and its run method executes in the Looper thread associated with the handler
Public Final Boolean post (Runnable R)
{
Note Getpostmessage (R) encapsulates runnable as a message
Return sendmessagedelayed (Getpostmessage (R), 0);
}
Private final Message Getpostmessage (Runnable r) {
Message m = Message.obtain (); Get an empty message
M.callback = R; Set the runnable as the callback of the message,
return m;
}
public boolean sendmessageattime (Message msg, long Uptimemillis)
{
Boolean sent = false;
MessageQueue queue = Mqueue;
if (queue! = null) {
Msg.target = this; The target of the message must be set to the handler!
Sent = Queue.enqueuemessage (msg, uptimemillis);
}
else {
RuntimeException e = new RuntimeException (
This + "sendmessageattime () called with no Mqueue");
LOG.W ("Looper", E.getmessage (), E);
}
return sent;
}
Other methods are not listed, in short, through the handler issued by the message has the following characteristics:
1.message.target is the handler object, which ensures that the key code in the loop () method can be found when Looper executes to the message, which is the handler that handles it
Msg.target.dispatchMessage (msg);
Message sent by 2.post with callback as Runnable object
Handler processing messages
After the message is sent, see how handler handles the message. Message processing is done through the core method DispatchMessage (Message msg) and the Hook method handlemessage (Message msg), see Source code
//Process message, the method is called by Looper
public void dispatchmessage (message msg) {
if (msg.callback! = null) {
If message is set to callback, that is, runnable messages, processing callback!
Handlecallback (msg);
} else {
//If handler itself is set to callback, execute callback
if (mcallback! = null) {
/* This method allows the Handler.callback interface to be implemented by the activity and so on, avoiding writing the handler rewrite Handlemessage method. See http://alex-yang-xiansoftware-com.iteye.com/blog/850865 */
if (Mcallback.handlemessage (msg)) {
Return
}
}
//If the message has no callback, call handler's Hook method handlemessage
H Andlemessage (msg);
}
}
//processing runnable message
Private final void handlecallback (Message message) {
Message.callback.run (); Call the Run method directly!
}
//Hook method implemented by subclass
public void Handlemessage (Message msg) {
}
As you can see, except for the Handlemessage (Message msg) and Runnable objects, the Run method is implemented by the developer (implementing specific logic), and the internal working mechanism of handler is transparent to the developer. That's what makes the handler API design so subtle!
The usefulness of handler
I described handler as "the Master of Asynchronous processing" in a small title, thanks to Handler's two key features:
1.handler can send messages on any thread that is added to the associated MQ.
2.handler is the processing of messages in its associated looper thread .
This solves the problem of Android's classic inability to update the UI in other non-main threads. the main thread of Android is also a looper threading (Looper is widely used in Android), the handler we create in it will be associated with the main thread MQ by default. Thus, one solution of handler is to create handler in the activity and pass its reference to the worker Thread,worker thread to send a message to notify the activity update UI after performing the task. Process
The sample code is given below for reference only:
public class Testdriveractivity extends Activity {
Private TextView TextView;
@Override
protected void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
Setcontentview (R.layout.main);
TextView = (TextView) Findviewbyid (R.id.textview);
Create and start a worker thread
Thread workerthread = new Thread (new Sampletask (New MyHandler ()));
Workerthread.start ();
}
public void AppendText (String msg) {
Textview.settext (Textview.gettext () + "\ n" + msg);
}
Class MyHandler extends Handler {
@Override
public void Handlemessage (Message msg) {
String result = Msg.getdata (). getString ("message");
Update UI
AppendText (result);
}
}
}
public class Sampletask implements Runnable {
private static final String TAG = SampleTask.class.getSimpleName ();
Handler Handler;
Public Sampletask (Handler Handler) {
super ();
This.handler = handler;
}
@Override
public void Run () {
try {//Simulate perform a task, download etc
Thread.Sleep (50 00); Notify activity update UI after the
//task completes
Message msg = preparemessage ("task completed!");
//message will be added to the main thread's MQ
Handler.sendmessage (msg);
} catch (Interruptedexception e) {
Log.d (TAG, "interrupted!");
}
}
Private message preparemessage (String str) {
Message result = HANDLER.OBT Ainmessage ();
Bundle data = new bundle ();
data.putstring ("message", str);
Result.setdata (data);
return result;
}
}
Of course, handler can do far more than that, because it can post runnable object, it can also be combined with looper to achieve the classic pipeline thread (pipelined threading) mode. Please refer to this article "Android Guts:intro to Loopers and handlers"
Encapsulate Task Message
In the entire message processing mechanism, message is called a task, encapsulating the information carried by the task and the handler that handles the task. The use of the message is relatively simple and is not summed up here. But there are a few points to note (to add):
1. Although the message has a public default constructor, you should use Message.obtain () to obtain an empty message object from the message pool to conserve resources.
2. If your message only needs to carry simple int information, prioritize using MESSAGE.ARG1 and message.arg2 to pass information, which is more memory-saving than using bundles
3. Use Message.what to identify information so that you can handle the message in different ways.
PS: Write for a long time ah, feel good words to a recommendation Oh Pro
Welcome reprint, but reprint please indicate source http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html
"Go" Android message processing mechanism (figure + source analysis)--looper,handler,message