Before analyzing the Android messaging mechanism, let's look at a piece of code:
Public classMainactivityextendsActivityImplementsView.onclicklistener {PrivateTextView Statetext; PrivateButton btn; @Override Public voidonCreate (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 voidOnClick (View v) {NewWorkthread (). Start (); } //Worker Threads Private classWorkthreadextendsThread {@Override Public voidrun () {//...... Handle more time-consuming operations//Change status after processing is completeStatetext.settext ("Completed"); } }}
This code seems to look normal, but when you run it you will find that 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, you must update it in the main thread, and you cannot perform the updated operation on the 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 modify the above code a little bit:
Public classMainactivityextendsActivityImplementsView.onclicklistener {Private Static Final intCompleted = 0; PrivateTextView Statetext; PrivateButton btn; PrivateHandler Handler =NewHandler () {@Override Public voidhandlemessage (Message msg) {if(Msg.what = =completed) {Statetext.settext ("Completed"); } } }; @Override Public voidonCreate (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 voidOnClick (View v) {NewWorkthread (). Start (); } //Worker Threads Private classWorkthreadextendsThread {@Override Public voidrun () {//...... Handle more time-consuming operations//send message to Handler when processing is completeMessage msg =NewMessage (); 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 inform the main thread, the main thread to update the view, the process of the message mechanism plays an important role.
Let's look at 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 referenced the Windows message loop mechanism, and also 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, and 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 ().
As mentioned earlier, both the message queue and message loop for Android are specific threads, one thread can have a message queue and a message loop, and a particular thread's message can only be distributed to this thread, and cannot be communicated across threads and across processes. However, the worker threads created by default do not have Message Queuing and message loops, and if you want the worker thread to have Message Queuing and message loops, you will 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 extends Thread { public Handler mhandler; Public void run () { looper.prepare (); New Handler () { publicvoid handlemessage (Message msg) { // processing the received message } }; Looper.loop (); } }
In this way, the worker threads we create have a message handling mechanism.
So why do we not see Looper.prepare () and Looper.loop () calls in the preceding example? The reason is that our activity is a UI thread that runs in the main thread, and the Android system creates a message queue and message loop for the activity when it starts.
The most mentioned is Message Queuing (MessageQueue) and message loop (Looper), but we see that every message processing place has a 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, you can specify a Looper object that is created with the Looper object of the current thread if not specified. Here are the two construction methods for 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. */ 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; }/*** Use the provided queue instead of the default one. */ PublicHandler (Looper Looper) {mlooper=Looper; Mqueue=Looper.mqueue; Mcallback=NULL; }
Here is a diagram of several important members of the messaging mechanism:
In one activity, multiple worker threads can be created, and if those threads put their messages in the message queue of the activity's main thread, the message is processed in the main thread. Because the main thread is generally responsible for updating the view component, this is a good way to implement the view update 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? As long as the handler object is created with the looper of the main thread, 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 child 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, and that data inconsistencies will occur during the sending and processing of messages. The answer is that there is no problem with the handler object, because the Looper object managed by the handler object is thread-safe, regardless of whether the message is added to the message queue or read from the message queue is synchronously protected, so there is no data inconsistency.
In-depth understanding of the Android message processing mechanism is very important for application development, but also allows us to have a deeper understanding of thread synchronization, I hope this article can help friends.
A brief analysis of the message mechanism in Android.