Some thoughts on handler in Android

Source: Internet
Author: User

This article includes the following issues related to handler:

(1) The role of handler

(2) Why is Android designed to update the UI only in the UI thread?

(3) Two exceptions to Handler

(4) The relationship between Handler and Looper MessageQueue (source angle)

(5) Thread-related handler, i.e. handlerthread (source angle analysis)

(6) The main thread sends messages to the child thread

First, the role of handler:

(1) To complete the time-consuming operation in a non-UI thread to update the UI in the UI thread.

(2) The delay message can be sent in the main thread.

Second, why should Android be designed to update the UI only in the UI thread?

(1) solving multi-threaded concurrency problems (root cause)

(2) Improve the performance of interface updates

(3) Simple architecture Design

You might say, since it's worrying about multithreading concurrency, do I have to add a lock on a child thread to update the UI line? If you think like that, it can easily cause the UI to stutter.

Note 1: It is difficult for most interviewers to say an answer that satisfies the interviewer.

NOTE 2: For multi-threading, here is an example, such as a bank withdrawal problem. Under normal circumstances, the bank card balance can not be less than the withdrawal amount, if the multi-threaded withdrawals, it will cause thread insecurity.

Note that the architecture is simple in 3:android because it encapsulates many of the actions that update the UI.

III. Two exceptions for handler:

When using handler, the following two exceptions are often encountered:

(1) Calledfromwrongthreadexception: This exception is due to an attempt to update the UI in a child thread, resulting in an exception.

(2) Can ' t create handle inside thread that ha called looper.prepared: It is the exception that is generated because we are going to create handler in the child thread.

We'll go through the code to illustrate the two exceptions.

1. Update UI exceptions in child threads:

(1) Activity_main.xml:

<relativelayout xmlns:android= "http://schemas.android.com/apk/res/android"                xmlns:tools= "http// Schemas.android.com/tools "                android:layout_width=" match_parent "                android:layout_height=" Match_parent "                tools:context= ". Mainactivity ">    <textview        android:id=" @+id/tv "        android:layout_width=" Wrap_content        " android:layout_height= "Wrap_content"        android:text= "@string/hello_world"/>    <button        android: Id= "@+id/btn"        android:layout_width= "match_parent"        android:layout_height= "Wrap_content"        android: text= "button"/></relativelayout>

In the code above, a text, a button, the code is relatively simple.

(2) Mainactivity.java:

1 Import android.app.Activity; 2 Import Android.os.Bundle; 3 Import Android.view.View; 4 Import Android.widget.Button; 5 Import Android.widget.TextView; 6 7 public class Mainactivity extends Activity {8 9 private TextView tv;10 private Button btn;11 @Overri De13 protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); setc Ontentview (r.layout.activity_main); TV = (TextView) Findviewbyid (r.id.tv); btn = (Button) Findviewbyid (R.ID.BTN); 18 19//After clicking the button, try updating the UI20 Btn.setonclicklistener (new View.onclicklistener () {21 @) in the child thread                     Override22 public void OnClick (View v) {new Runnable () {25 @Override26 public void Run () {tv.settext ("smyhvae"); Updating the UI in a child thread}29}). Start (); 30 31}32}); 33}34}

In the above code, the core code is line 27th: After clicking the button, update the UI in the child thread.

After running the program, click the button, the effect is as follows:

At this point, let's look at the log log in the background:

The error log in the report is because we are updating the UI in a child thread.

Solution:

creates a message in a child thread, sends the main thread through handler, and then obtains a message in the handler Handlemessage method to handle the update UI interface . The code is as follows:

 1 Import android.app.Activity; 2 Import Android.os.Bundle; 3 Import Android.os.Handler; 4 Import Android.os.Message; 5 Import Android.view.View; 6 Import Android.view.View.OnClickListener; 7 Import Android.widget.Button; 8 Import Android.widget.TextView; 9 public class Mainactivity extends Activity implements Onclicklistener {One public static final int update_text = 1 ; TextView text;13 Private Button changetext;14 15//program one load, directly in the main thread to create Handler16 private Handler ha             Ndler = new Handler () {public void Handlemessage (Message msg) {19 switch (msg.what)                 Case update_text:20 Text.settext ("Nice to meet"); Break;22 default:23 break;24}25}26};27 @Override29 protected void onCreate (Bundle Savedin Stancestate) {super.oncreate (savedinstancestate); Setcontentview (R.layout.activity_main); ext = (TEXTVIew) Findviewbyid (r.id.text); changetext = (Button) Findviewbyid (r.id.change_text); Changetext.setoncl         Icklistener (this);}36 PNs @Override38 public void OnClick (View v) {40 switch (V.getid ()) Case r.id.change_text:41 New Thread (new Runnable () {@Override43 public voi D run () {A . Message message = new Message ();Message.what = update_text;46 handler.sendmessage (message); 47} ). Start (); break;50 default:51 break;52}53}54}

The 44th line of code above can also be replaced by:

Message message = Handler.obtainmessage ();

2. Create the handler exception in the child thread:

Mainactivity.java:

1 Import android.app.Activity; 2 Import Android.os.Bundle; 3 Import Android.os.Handler; 4 Import Android.widget.TextView; 5  6 public class Mainactivity extends Activity {7  8     private TextView TV; 9     @Override11     protected V OID onCreate (Bundle savedinstancestate) {         super.oncreate (savedinstancestate);         Setcontentview ( R.layout.activity_main);         TV = (TextView) Findviewbyid (r.id.tv);         try to create Handler17 new thread in a sub-thread         (New Runnable () {             @Override19 public             void Run () {                 new Handler ();             }22         }). Start (); 23     }24}

After running the program, the error is as follows:

iv. Relationship between Handler and Looper MessageQueue:(source angle)

If you want to ask handler, this question is basically the interview must ask.

Principle Analysis:

Handler is a processing class provided by the Android class library for sending, processing, or runnable objects, which combines the message, MessageQueue, and Looper classes with the current thread to implement a messaging loop mechanism for asynchronous loading and processing of tasks. The entire asynchronous message processing flow is as follows:

Based on the picture above, let's now parse the asynchronous message processing mechanism :

    • message: A body of messages that is used to load objects that need to be sent.
    • Handler: It inherits directly from object. The function is to send a message or Runnable object to MessageQueue in a child thread, or to receive, process, or manipulate a message or Runnable object distributed from MessageQueue in the UI thread. Sending a message typically uses the handler SendMessage () method, and the outgoing message is processed and eventually passed to Handler's Handlermessage () method.
    • MessageQueue: A message queue for storing messages or runnable objects. It is created by the corresponding Looper object and managed by the Looper object. There will only be one MessageQueue object in each thread.
    • Looper: Is the steward of MessageQueue in each thread, responsible for receiving and distributing the work of message or runnable. Calling the Looper.loop () method is a dead loop that constantly takes messages from the MessageQueue: if there is a message, take it out and call handler's Handlermessage () method, if no message is blocked.

The following summary can now be made:

(1) handler is responsible for sending messages, Looper is responsible for receiving handler sent messages to Messagequeue,looper and send the message back to handler himself.

(2) A handler corresponds to a Looper object, a looper corresponds to a MessageQueue object (Looper inside contains a MessageQueue), and a handler can generate multiple message.

(3) handler is the interface that is exposed to external threads for communication between threads. Looper is a system-supported loop processing object that is used to create and manage MessageQueue that is attached to a thread, and handler is used to manipulate the message queues inside the thread, so handler must also be attached to a thread and can only be a thread.

(4) Since handler is created in the main thread, the code in the Handlemessage () method will also run in the main thread, so we can do the UI operation safely here.

Examples of life:

, it can be understood that: in the meeting, I (Handler) want to go halfway to do something else, through the SendMessage to send messages to the leadership, leadership thinking for a while, after agreeing, through the Looper.looep () method to send the message back to me, said I can leave, Then I called the Handlemessage method to do something else.

Note: When interviewing, if just from the literal angle to explain the relationship between handler, Looper MessageQueue, can not really impress the interviewer, it is better to give a vivid example, let the interviewer think you understand the object-oriented thinking.

v. Thread-related handler, i.e. Handlerthread(source angle analysis)

This is a question you can look at in this blog post:

http://blog.csdn.net/lmj623565791/article/details/47079737

Six, the main thread to the child thread message : (see if you really understand the handler mechanism)

In our usual development process, it is often a child thread that sends a message to the main thread, allowing the main thread to update the UI. However, depending on the project requirements, you may also be asked to send messages to child threads in the main thread.

 1 Import android.app.Activity; 2 Import Android.os.Bundle; 3 Import Android.os.Handler; 4 Import Android.os.Looper; 5 Import Android.os.Message; 6 Import Android.util.Log; 7 Import Android.view.View; 8 Import Android.view.View.OnClickListener; 9 Import android.widget.button;10 Import android.widget.textview;11 public class Mainactivity extends Activity impleme NTS Onclicklistener {public static final int update_text = 1;14 private TextView tv;15 private Button btn;1 6 Private Handler handler;17 @Override19 protected void onCreate (Bundle savedinstancestate) {+ SUP Er.oncreate (savedinstancestate); Setcontentview (r.layout.activity_main); TV = (TextView) Findviewbyid ( r.id.tv), btn = (Button) Findviewbyid (R.ID.BTN), Btn.setonclicklistener (this), 25//Question: Why does this code The result is written in the OnClick method will be reported null pointer? New Runnable () {@Override28 public void run () { 29//1, Prepare Looper object Looper.prepare (), 31//2, create Handler32 in child threads Handler = new Handler () {@Override34 public void Handlemessage (Messa GE msg) {super.handlemessage (msg); LOG.I ("Handlemessage:", thread.cur Rentthread (). GetName ()), PNs log.i ("Background output", "received Message object"); 38}39};4 0//3, call Looper Loop () method, take out the Message Object Looper.loop (); }43}). Start (),}46 @Override47 public void OnClick (View v) {log.i ("OnC Lick: ", Thread.CurrentThread (). GetName ()); switch (V.getid ()) {case r.id.btn:51 M             Essage msg = Handler.obtainmessage (); Handler.sendmessage (msg); break;54 55 default:56 break;57}58}59}

Line 29th through 41 lines of code above: This is a fixed notation for sending messages in Mainthread and receiving messages in a child thread . Repeat the three steps above:

    • Preparing Looper objects
    • Generate a Handler object in Workerthread
    • After calling Looper's Loop () method, the Looper object will continuously take the object from the message queue and then call handler's Handlemessage () method to process the message object, which is blocked if there are no objects in the message queue

Note that at this point the Handlemessage () method is running in a child thread.

Background Run Effect:

Briefly summarize:

The Looper prepare () method is executed first, which has two functions: one is to generate the Looper object, and the Looper object and the current thread object form a key-value pair (line Chengwei), stored in the threadlocal, and then generated handler object, Call Looper's Mylooper () method to get the Looper object that corresponds to handler, so handler, looper, Message Queuing form a one by one corresponding relationship, then perform the third step above, That is, looper the data that is looped in the message queue.

Also, in the first paragraph at the beginning of this article, we created handler in the main thread and didn't call the Looper.prepare () method, why didn't it crash? , this is because the system has automatically called the Looper.prepare () method when the program is started. To view the main () method in Activitythread, the code looks like this:

1 public static void main (string[] args) {   2     samplingprofilerintegration.start ();   3     closeguard.setenabled (false);   4     Environment.initforcurrentuser ();   5     Eventlogger.setreporter (New Eventloggingreporter ());   6     process.setargv0 ("<pre-initialized>");       looper.preparemainlooper ();   8     Activitythread thread = new Activitythread ();   9     Thread.attach (false);  Ten     if (Smainthreadhandler = = null) {One         Smainthreadhandler = Thread.gethandler ();     asynctask.init ();     if (false) {         looper.mylooper (). setmessagelogging (New Logprinter (Log.debug, "Activitythread")) ;     looper.loop ();     -throw new RuntimeException ("Main thread loop unexpectedly exited");  19}  

In the above code, you can see that the Looper.preparemainlooper () method is called in line 7th, and this method again calls the Looper.prepare () method, as shown in the following code:

1 public static final void Preparemainlooper () {  2     prepare ();  3     Setmainlooper (Mylooper ());  4     if (process.supportsprocesses ()) {  5         mylooper (). mqueue.mquitallowed = false;  6     }  

Summary: This basically will handler the creation process completely understand, summarize is in the main thread can directly create the handler object, and in the child thread first call Looper.prepare () to create the handler object.

Vi. Why in some cases a child thread can update the UI directly:

This question should be one of the most difficult interview questions in this article, need to understand well. In order to answer this question, we need to first look at the source code to understand the following three questions:

(1) How Android detects non-UI threads to update the UI

(2) What is Viewrootimp?

(3) Where was the viewrootimp created?

I will not post the source code, here I just summed up.

Answer:

non-UI line threads can not update the UI ?

Explain:

the Viewparent.invalidatechild () method is called when the UI is updated in a thread to check whether the current thread is Mainthread.

The specific source code is as follows:

1 final viewparent p = mparent;2     if (p! = NULL && AI! = null && l < R && T < b) {3     F inal Rect damage = ai.mtmpinvalrect;4     Damage.set (L, T, R, b);  5     P.invalidatechild (this, damage); 4?

And Viewparent is an interface class, its implementation class is Viewrootimpl, by looking at the Invalidatechild () method inside the code can see that he calls the Checkthread () method. The Checkthread () method is as follows:

1 void Checkthread () {2     if (mthread! = Thread.CurrentThread ()) {   //check if the thread updating UI is MainThread3         throw new Calledfromwrongthreadexception (4         "only the original thread, that created a view hierarchy can touch it views."); 5     }6}

The No. 02 line above is check: whether the thread is mainthread when the UI is updated in the thread.

However, theViewrootimpl class is created in the activity's Onresume () method . Even if the UI is updated in a child thread, as long as the UI is updated before Viewrootimpl is created (for example, when the program executes the OnCreate method, I go to the SetText method area update UI), you can evade the Checkthread () check.

On the subject, give the following links to read the source code:

Android Update UI Advanced Fine Solution (i):

Http://www.jianshu.com/p/6de0a42a44d6

Why we can update the UI in a non-UI thread:

Http://blog.csdn.net/aigestudio/article/details/43449123

Some thoughts on handler in Android

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.