Android: complaints between Handler, Looper, and MessageQueue in asynchronous processing (3) and loopermessagequeue

Source: Internet
Author: User
Tags sendmsg

Android: complaints between Handler, Looper, and MessageQueue in asynchronous processing (3) and loopermessagequeue

Preface

If you do not know what Handler is in Android before reading this article, I suggest you read the first blog in this series: Android: handler + Thread application of asynchronous processing (1); we all know that the UI interface cannot be directly updated in the Child Thread in the Android system, therefore, we usually use Handler + Thread or AsyncTask to update the UI. Handler + Thread is actually a set of mechanisms by which the subthread transmits messages to the UI main Thread and notifies the UI main Thread to update the interface. Sometimes the interviewer prefers to test your Handler mechanism, so it is quite necessary to study the communication mechanism in depth based on the source code. If you can despise the interviewer, haha o (Clerk □clerk) o ..

Overview

Google's messaging mechanism was designed with reference to windows. We don't care about patent litigation between uncle and uncle. Generally, threads use logoff to establish their own Message loops and lock a FIFO Message Queue MessageQueue. Handler uses logoff to achieve Message (Message) Access in MessageQueue. Each Hanlder automatically or manually binds a logoff to indirectly send a Message to a MessageQueue during instantiation. Therefore, Handler also encapsulates the interface for sending and receiving messages.

Example

Looking at the summary, it's boring to think about the text. It's obscure and hard to understand. Remember that it's another big problem. Let's take a look at the example here. So I wrote an example here to send messages to the subthread and display the output. I want to explain it to the subthread.

The main code is as follows:

Public class MainActivity extends ActionBarActivity {private Handler handler; private Button btn; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); btn = (Button) findViewById (R. id. sendmsg); new HandlerThread (). start (); // promoter thread btn. setOnClickListener (new OnClickListener () {@ Override public void onClick (View v) {handler. sendEmptyMessage (0); // send a message to the subthread});} class HandlerThread extends Thread {@ Override public void run () {// start to establish a message loop logoff. prepare (); // initialize loveshandler = new handler () {// by default, loves@override public void handleMessage (Message msg) {switch (msg. what) {case 0: Toast. makeText (MainActivity. this, "The subthread receives the message", Toast. LENGTH_SHORT ). show () ;}}; logoff. loop (); // start the message loop }}}

Layout file:

<LinearLayout 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" android: orientation = "vertical"> <Button android: id = "@ + id/sendmsg" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: text = "blow a gun to the subthread! "/> </LinearLayout>

We only need to click the button to send the message successfully .....

Let me briefly describe the message sending process:

1. Start a subthread and initialize a logoff in the subthread.

2. Handler is instantiated in HandlerThread, and Handler is automatically bound to the Logoff of the current thread.

3. Rewrite the Message Processing Method in Handler.

4. Execute logoff. loop () to start the message loop, and the sub-thread enters the waiting message status.

A small study

Of course, it is easy to understand only by explaining the examples. We will explore the establishment of a message loop, the principles of message distribution and processing by combing the preceding message sending process and the source code.

1. logoff Initialization

Go to logoff to view the source code:

public static void prepare() {  prepare(true);}private static void prepare(boolean quitAllowed) {  if (sThreadLocal.get() != null) {    throw new RuntimeException("Only one Looper may be created per thread");  }  sThreadLocal.set(new Looper(quitAllowed));}

When we call the logoff prepare static method, we find that this thread creates a logoff instance and assigns it to the local variable of the thread sThreadLocal, of course, we can be sure that this sThreadLocal is private to the current thread, and we don't believe that we don't believe it. Next we will look at the logoff constructor.

private Looper(boolean quitAllowed) {  mQueue = new MessageQueue(quitAllowed);  mThread = Thread.currentThread();}

Believe that everyone's eyes are bright, right ?! In logoff (), A Message Queue (MessageQueue) is instantiated )! As we wish to bind it to the mQueue local variable, here we can draw a conclusion: Call loue. the prepare () thread creates a message loop object,! The message loop event has not yet started.

2. instantiate Handler and bind the Logoff of the current thread

Let's take a look at Handler's source code -- Handler's constructor.

public Handler() {  this(null, false);}public Handler(Callback callback, boolean async) {  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());    }  }  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 = callback;  mAsynchronous = async;}

In the code, we call the handler (Callback callback, boolean async) method through Handler = new Handler (); we find that mloler = Looper. myloue () binds the Looper in the thread to the Handler and uses mQueue = mloue. mQueue obtains the thread message queue. I can also put it another way: Handler has been bound to the Message Queue of the thread that created this Handler object, so we can start to do bad things ....

3. Override handleMessage () method of Handler

public void handleMessage(Message msg) {}

There is no such thing as an empty method. It provides our override entry function.

4. Start the message loop through logoff. loop ()

Or the above idea, we will go into loop () to see if there will always be gains ..

public static void loop() {  final Looper me = myLooper();  if (me == null) {    throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");  }  final MessageQueue queue = me.mQueue;
  Binder.clearCallingIdentity();  final long ident = Binder.clearCallingIdentity();  for (;;) {    Message msg = queue.next(); // might block    if (msg == null) {      return;    }    Printer logging = me.mLogging;
    if (logging != null) {      logging.println(">>>>> Dispatching to " + msg.target + " " +        msg.callback + ": " + msg.what);    }    msg.target.dispatchMessage(msg);    if (logging != null) {      logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);    }    final long newIdent = Binder.clearCallingIdentity();      if (ident != newIdent) {        Log.wtf(TAG, "Thread identity changed from 0x"              + Long.toHexString(ident) + " to 0x"              + Long.toHexString(newIdent) + " while dispatching to "              + msg.target.getClass().getName() + " "              + msg.callback + " what=" + msg.what);      }    msg.recycle();
  }}

In the static method of loop (), we can notice the for (;) method, which is a dead loop, so we call it a "message loop ", it seems like an image. In the message loop, the queue. next () is called to obtain the messages waiting for processing in the queue and assign them to the msg variable. next, you can determine if msg is used! = If this parameter is set to null, start message and split message is enabled. msg.tar get. dispatchMessage (msg) is also executed ). After the split message ends, the message will be recycled, as shown in msg. recycle.

Msg.tar get is a handler object, indicating the handler object that needs to process the message. So let's go back to Handler and look at the dispatchMessage () method:

public void dispatchMessage(Message msg) {  if (msg.callback != null) {    handleCallback(msg);  } else {    if (mCallback != null) {      if (mCallback.handleMessage(msg)) {        return;      }    }    handleMessage(msg);  }}

I don't know if you have found the handleMessage () method at a Glance. Isn't this the way we rewrite Handler in step 3. When msg. callback! = Null and mCallback! = If it is null, handleMessage (msg) will be called to process messages sent by other threads. We will overwrite this method to implement our specific message processing process; this is all the content of the Handler message processing mechanism.

Make a summary.

By reading the full text, we can know that the core of the message loop mechanism is logoff, because logoff holds the MessageQueue object and can be set as a local variable by a thread, we can think that this thread has a message queue through logoff. Handler is used to encapsulate the methods for sending and processing messages. In the online communication, the thread can send messages to the thread that creates Handler through Handler, put the message into the message queue of the message receiving thread through logoff, wait for Logoff to retrieve the message and finally give it to Handler to process the specific message.

Another sentence

We will find that the logoff is not required to instantiate a Handler in the Activity. prepare () to initialize a logoff and logoff. loop () to start the message loop, because the Activity has initialized logoff and established a message loop during the construction process. For more information, see ActivityThread. code in java:

public final class ActivityThread {    public static final void main(String[] args) {        ......        Looper.prepareMainLooper();        ......        ActivityThread thread = new ActivityThread();        thread.attach(false);        ......        Looper.loop();        ......        thread.detach();        ......    }}

When the Android application process starts, it loads the ActivityThread class in the process and executes the main function of this class. The message loop process of the application is implemented in this main function; if you want to learn more, we suggest you study the Activity startup mechanism.

 

By enjoy wind chimes
Source:Http://www.cnblogs.com/net168/
The copyright of this article is shared by the author and the blog Park. You are welcome to reprint this article. However, you must keep this statement without the author's consent and provide a connection to the original article clearly on the article page. Otherwise, you will not be reposted next time.


Handler problems in ANDROID

Handler is not equal to the thread used.
Traditional UI architecture, such as swing. Place the rendering display and event distribution in the main thread (UI) thread.
The implementation model of the UI thread is usually an endless loop that constantly accepts messages. Organization distribution
In android, Handler-MessageQueue-Logoff forms the model of this endless loop + message communication. PostDelayed actually puts a Runnable task into MessageQueue and is expected to be executed in 3000 milliseconds.
In addition, do not mistakenly think that Runnable is a thread. In java. util. concurrent, Dogn has clearly separated the execution process from the task. The Runnable interface only indicates a task that can be executed simultaneously or in a new thread.
Why Handler instead of Thread. In addition to the classic mode of the UI framework, the message model also involves the restriction that the UI components do not allow cross-thread access. Whether it is. NET, swing, or android, operations in non-UI threads are not allowed.
Handler is the official channel for asynchronous thread code in the android framework to reach the synchronization thread. From another perspective, this message-based communication mode is sometimes useful. Related examples include IntentService and HandlerThread.

How to Use the Android Handler mechanism?

The Handler object is in the same thread as its caller. If a delayed operation is set in Handler, the calling thread will also be blocked. Each Handler object is bound to a logoff object, and each logoff object corresponds to a Message Queue (MessageQueue ). If the logoff object bound to the Handler is not specified when the Handler is created, The logoff object of the current thread is bound to the Handler by default.
In the main thread, you can directly use new Handler () to create a Handler object, which will be automatically bound to the logoff object of the main thread. If Handler is directly created in a non-main thread, an error will be reported, the Android system does not enable logoff in the main thread by default, and the Handler object must be bound to the logoff object. In this case, you must manually enable logoff in this thread. prepare () --> logoff. loop (), and then bind it to the Handler object; or use logoff. getMainLooper () to obtain the Looper of the main thread and bind it to this Handler object.
All the messages sent by Handler are added to the logoff MessageQueue. Handler contains two queues: thread queue and message queue. post () can add the thread object to the thread queue; Use Handler. sendMessage () can be used to add a message object to a message queue. The source code analysis shows that Handler has only one message queue, namely, MessageQueue. The thread object passed through post () will be encapsulated into a message object and passed into MessageQueue.
After a thread object is put into a Message Queue using post (), when logoff polls the thread for execution, it does not actually start a new thread separately, but it is still executed in the thread bound to the current logoff. Handler only calls the run () of the thread object. For example, the UI update command is defined in the Child thread. If the thread is directly enabled for execution, an error is reported () add it to the Logoff of the main thread and execute it to update the UI.
After you use sendMessage () to add a message object to a message queue, when logoff polls the message, handleMessage () of Handler is called to process it. Taking UI update as an example, if this method is used, the Logoff of the main thread is first bound to the Handler object, and handleMessage () is overloaded to process UI updates, then you can send a message to it.

Related Article

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.