Before analyzing the Android messaging mechanism. Let's look at a piece of code first:
public class Mainactivity extends Activity implements View.onclicklistener { private TextView statetext; Private Button btn; @Override public void OnCreate (Bundle savedinstancestate) { super.oncreate (savedinstancestate); Setcontentview (r.layout.main); Statetext = (TextView) Findviewbyid (r.id.tv); BTN = (Button) Findviewbyid (R.ID.BTN); Btn.setonclicklistener (this); } @Override public void OnClick (View v) { new Workthread (). Start (); Worker thread Private class Workthread extends thread { @Override public void Run () { //... Change the status statetext.settext ("completed") after processing time-consuming operations//processing finishes; } }
This code seems to look very normal, but you will find it when you execute it. It will report a fatal exception:
Error/androidruntime (421): FATAL exception:thread-8error/androidruntime (421): android.view.viewroot$ Calledfromwrongthreadexception:only the original thread that created a view hierarchy can touch it views.
What the hell is going on here? The reason is that the view components in the Android system are not thread-safe, and if you want to update the view, it must be updated in the main thread. The update operation cannot be run in a child thread.
In this case, we will notify the main thread in the child threads, let the main thread do the update operation. So, how do we notify the main thread? We need to use the handler object.
Let's change the above code a little bit:
public class Mainactivity extends Activity implements View.onclicklistener {private static final int completed = 0;private TextView statetext;private Button btn;private Handler Handler = new Handler () {@Overridepublic void Handlemessage (Message msg) {if (Msg.what = = completed) {statetext.settext ("completed");}}; @Override public void OnCreate (Bundle savedinstancestate) { super.oncreate (savedinstancestate); Setcontentview (r.layout.main); Statetext = (TextView) Findviewbyid (r.id.tv); BTN = (Button) Findviewbyid (R.ID.BTN); Btn.setonclicklistener (this); } @Overridepublic void OnClick (View v) {new Workthread (). Start ();} Worker thread private class Workthread extends thread {@Overridepublic void run () {//... Processing time-consuming operations//processing finished send message to handler msg = new Message (); msg.what = Completed;handler.sendmessage (msg);}}
In this way, we can solve the problem of thread safety, the complex task processing to the child thread to complete, and then the child thread through the handler object to tell the main thread, the main thread to update the view. In this process, the messaging mechanism plays a key role in the data.
Below, let's analyze the message mechanism in Android.
A friend familiar with Windows programming knows that Windows programs are message-driven and have a global messaging system.
Google has been involved in the Windows message loop mechanism and has implemented a message loop mechanism in the Android system. Android uses Looper, handler to implement the message loop mechanism. The message loop for Android is thread-specific. Each thread can have its own message queue and message loop.
The Looper in the Android system is responsible for managing thread Message Queuing and message loops. The Looper object of the current thread is obtained through Looper.mylooper (), and the Looper object of the current process's main thread is obtained through Looper.getmainlooper ().
mentioned earlier. Both the message queue and message loop for Android are for detailed threading, a thread can have a message queue and a message loop, and a particular thread's message can only be distributed to this thread. You cannot communicate across threads and across processes. However, the worker threads created by default do not have message queues and message loops. Assuming that you want a worker thread to have a message queue and a message loop, you need to call Looper.prepare () to create the message queue in the thread, and then call Looper.loop () to enter the message loop. Here are the worker threads we created:
Class Workthread extends Thread {public Handler Mhandler; public void Run () { looper.prepare (); Mhandler = new Handler () {public void Handlemessage (Message msg) { //processing received message } }; Looper.loop (); } }
So. The worker thread we created has a message handling mechanism.
So. Why do we not see Looper.prepare () and Looper.loop () calls in the demo example? The reason is that our activity is a UI thread. Execution in the main thread, the Android system creates a message queue and message loop for the activity when it starts.
The most mentioned above are Message Queuing (MessageQueue) and message loop (Looper). But we see every message processing place has handler existence, what does it do? The role of handler is to add messages to a message queue that is managed by a particular looper, and to distribute and process messages in that message queue. When constructing handler, it is possible to specify a Looper object, assuming that the Looper object created by the current thread is not specified. The following are the two construction methods of handler:
/** * Default Constructor Associates This handler with the ' queue for the ' * current thread. * * If there isn ' t one, this handler won ' t is able to receive messages. */Public Handler () {if (Find_potential_leaks) {final class<? extends handler> Klass = Getcla SS (); if (Klass.isanonymousclass () | | klass.ismemberclass () | | klass.islocalclass ()) && (Klass.getmo Difiers () & 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 has Not called Looper.prepare () "); } mqueue = Mlooper.mqueue; Mcallback = null; }/** * Use the provided queue instead of the default one. */Public HandlER (Looper Looper) {mlooper = Looper; Mqueue = Looper.mqueue; Mcallback = null; }
The following is a diagram of several important members of the messaging mechanism:
One activity can create multiple worker threads, assuming that the threads put their messages in the message queue of the activity's main thread, then the message is processed in the main thread.
Because the main thread is generally responsible for the update operation of the view component, this is a good way to update the view for a view component that is not thread-safe.
So how does a child thread put the message into the message queue of the main thread? Simply handler objects are created with the looper of the main thread, then when the SendMessage method of handler is called, the system puts the message queue of the main thread of the message, and the message in the main thread message queue is processed when the Handlemessage method is called.
For a sub-thread to access the handler object of the main thread, you might ask that many sub-threads have access to the handler object of the main thread, will there be inconsistencies in the data when sending messages and processing messages? The answer is that the handler object does not fail, and because the Looper object managed by the handler object is thread-safe, whether the message is joined to the message queue or read from the message queue is synchronously protected, there is no data inconsistency.
Messaging mechanisms in Android