The asynchronous threading principle of Android

Source: Internet
Author: User

Basic introduction

The asynchronous message processing thread refers to a thread that enters a wireless loop body after it is started, does not loop once, pulls a message from the internal message queue, and calls back the corresponding message handler, and then resumes the loop after executing a message. If the message queue is empty, the thread pauses to know that there are new messages in the message queue.
The asynchronous message processing thread is still essentially a thread, except that the thread's execution code is set to the logic described above. Implementing asynchronous threading in Android involves several classes: Threadlocal,looper,messagequeue,handler,message, which describes the asynchronous threading mechanism of Android.

First, a frame chart:

ThreadLocal

Threadlocal is not a class in the SDK of Android, but a class in Java.lang, which is a class that creates a thread-based variable store for threads, which we can call thread-local storage. Threadlocal can enable an object to be thread-isolated, maintaining its own copy of the variable for each thread, and binding the variable to the thread by its set method. Threadlocal provides a solution to the problem of multithreading synchronization by copying each of the variables so that each thread operates on its own variables rather than a common one, so there is no need to synchronize locks. To give a chestnut, we create a variable that is manipulated by two threads. In general, we will lock this variable and solve the problem of synchronization in this way. But when we use Threaloca, we can make a copy of each thread through Threadloca, and the copy is bound to the thread, which means that each thread can change its own variable without affecting another thread. So there's no need for a lock. Threadlocal is automatically bound to the current thread when set, without having to bind itself. The code is not written here, the central idea is OK. One might ask, what does this have to do with Android? This is about our looper, because in the asynchronous thread of Android, the thread variable that threadlocal binds to is an object of Looper.

Looper

What's the use of looper? To implement an asynchronous thread, you must looper, because Looper is used to generate a MessageQueue. We can see from the source code that there is a member variable Mqueue (an instance of the MessageQueue class) in the Looper class that holds MessageQueue in Looper.
Looper creates a MessageQueue object by using the static method Looper.prepare () method. Note that the Looper.prepare () method can only be executed once in a thread.

Prepare () method

View Source code:

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));
}

The above is the Android source code, executed two times prepare, will throw an exception. This is actually very natural to think, because previously mentioned, Looper is used to create MessageQueue. A thread can have only one MessageQueue, so naturally there can be only one Looper object. Read prepare () source code does not seem to have found that it created an instance of MessageQueue Ah, right, here is not see, but. Let's take a look at the work done when creating a new Looper object:
We found the Looper constructor:

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

We can see that this constructor of Looper is private, and Looper only has this constructor. So we can see that we can't make a new Looper object in another class. But that's not the point, but the point is that Looper created a MessageQueue object here.

Loop () method

Loop static method is used to perform the looping of the message. Everyone should know that this is a dead loop. Used to continuously read messages in the message team. Let's look at the source code: The source code is as follows:

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;
Make sure the identity of the the the the The local process,
And keep track of the What, identity token actually is.
Binder.clearcallingidentity ();
Final Long ident = Binder.clearcallingidentity ();
for (;;) {
Message msg = Queue.next ();//might block
if (msg = = null) {
No message indicates that the message queue is quitting.
Return
}
This must is in a local variable with case a UI event sets the Logger
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);
}
Make sure that during the course of dispatching the
The identity of the thread wasn ' t corrupted.
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 ();
}
}

The function mylooper is used to return the Looper object of the current thread through a for (;;) To execute the loop. Inside the For loop, through the next method of MessageQueue to get out of the message, here is a point to note, is to take out the message, and finally call Msg.target.dispatchMessage (msg); To process the message, the method is in handler, because Msg.target is a handler object. Put it in the handler.

MessageQueue

The MessageQueue is used to process message queues. There are several methods in this class, one is the next () method, which is used to remove the next element in the queue. Another is the Enqueuemessage method, which is used to add an element to the message team. This method will be used in the SendMessage in handler, a little mention here, in Handler's SendMessage, this method is called to add the message to the MessageQueue of the receiving thread.

Handler

Handler is used to send information, the method we know is the SendMessage method, which is used to send messages to the message receiving thread. As stated in the above frame diagram, handler must be created in the thread that receives the message, so that the message can be sent to the thread. Because the created handler object handler must have MessageQueue Message Queuing for that thread to send a message to that thread. When handler is created, it uses the following constructor:

The handler constructor

Public Handler (Callback Callback, Boolean async) {
if (Find_potential_leaks) {
Final Class 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 have not called looper.prepare ()");
}
Mqueue = Mlooper.mqueue;
Mcallback = callback;
masynchronous = async;
}

When the handler is created, the Looper object of the current thread is obtained through Mlooper = Looper.mylooper (), and the Looper object is the precondition for acquiring the MessageQueue object. Handler is eventually called to this method when the message is sent by calling Handler.sendmessage (message):

Handler SendMessage method (the method that will eventually be called)

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
     MessageQueue queue = mQueue;
     if (queue == null) {
         RuntimeException e = new RuntimeException(
             this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e);         
            return false;
         }
     return enqueueMessage(queue, msg, uptimeMillis);
}

As you can see here, handler gets the MessageQueue object for the current thread. Then call Enqueuemessage (Queue, MSG, uptimemillis); This method is the method in handler, not the Enqueuemessage method in Messgaequeue, We look at the Enqueuemessage method in handler:

The Enqueuemessage in handler

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
     msg.target = this;
     if (mAsynchronous) {
     msg.setAsynchronous(true);
     }
     return queue.enqueueMessage(msg, uptimeMillis);
}

You can see the first line of code in a method body: Msg.target = This; Sets the currently sent Message.target object to the current handler. This is called Msg.target.dispatchMessage (msg) in the Looper.loop () method. This will be introduced soon. Let's not say this. As you can see, the Enqueuemessage method in handler sets the target of the message to the current object, and then calls the enqueuemessage of the MessageQueue object, which is described in MessageQueue. Is the method that is used to add messages to the message queue) method, which adds a message to the MessageQueue object.
OK, now let's take a look at Handler's DispatchMessage (msg) method. Let's take a look at the source code for this method, which is used in the Looper loop method, and when each message is fetched, the method Msg.target.dispatchMessage (msg) is invoked to process each message.

DispatchMessage

public void DispatchMessage (Message msg) {
         if ( Msg.callback! = null) {
             handlecallback (msg);
             } else {
              if (Mcallback! = null) {
              if (Mcallback.handlemessage (msg)) {
              return;
             }
         }
         handlemessage (msg);
    }
}

The method first to determine whether the message itself has a callback function, some call the message callback function, if not, then determine whether to create this handler when the callback interface is passed, note that the name of this interface is callback, Handler can assign a value to this mcallback by a constructor, and if the Mcallback passes the value, it will be called, otherwise the Handlemessage method of handler itself is called. This method is empty in handler and needs to be overridden in a class that inherits handler. This means that the overridden method is actually the least-privileged.
The following two kinds of common, but the previous one, that is, the message itself carries the interface of the general through the Message.obtain (Handler H, Runnable callback) method to set.
Okay, Android's async thread. It doesn't have much to do here.


The asynchronous threading principle of 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.