Android thread Management--thread communication

Source: Internet
Author: User

Thread communication, Activitythread, and thread classes are key to understanding Android threading management.

threads, as the basic unit of CPU scheduling resources, have a very important and fundamental role in the operating system for embedded devices such as Android. This section is mainly from the following three aspects of analysis:

    1. "Android thread management-thread communication"
    2. "Android Threading Management--activitythread"
    3. "Android Threading Management--thread"

I. Relationship of Handler, MessageQueue, message and Looper

Handler, MessageQueue, message, and looper are commonplace topics when developing Android multi-threaded applications. But to thoroughly clarify the relationship between them, it is necessary to study their respective implementation in depth. First, give a diagram of the relationship between them:

    • Looper relies on MessageQueue and thread, because each thread only corresponds to one looper, and each looper corresponds to only one MessageQueue.
    • MessageQueue relies on message, and each MessageQueue corresponds to multiple message. That is, the message is pressed into the MessageQueue to form a message collection.
    • The message relies on handler for processing, and each message specifies a maximum of one handler to handle. Handler relies on MessageQueue, Looper and callback.

From the operating mechanism, handler the message into the Messagequeue,looper continuously remove the message from the MessageQueue (when the MessageQueue is empty, into the sleep state), its target Handler is the message processing. Therefore, to thoroughly understand the thread communication mechanism of Android, you need to know the following three questions:

    • Handler message distribution, processing flow
    • Properties and operations of MessageQueue
    • How the Looper works
1.1 Handler's message distribution, processing flow

Handler mainly completes the queue of message (MessageQueue) and processing, the following will be through the handler source analysis of its message distribution, processing process. First, look at the list of methods for the handler class:

It can be seen that the method of handler class core includes: 1) constructor, 2) distributing message, 3) processing message, 4) post sending message; 5) send message; 6) remove message and callback.

First, from the construction method, the constructor's polymorphism is finally implemented by invoking the following method, which assigns the arguments to the internal domain of the handler class.

Final MessageQueue Mqueue; Final Looper Mlooper; Final Callback Mcallback; Final Boolean masynchronous;  Public Boolean async) {    = looper;     = Looper.mqueue;     = callback;     = Async;}

Secondly, the queue of messages is accomplished through the Post method and the Send method.

 Public Final Boolean Long Uptimemillis) {    return  sendmessageattime (Getpostmessage (R), Uptimemillis);}
 Public Final boolean sendemptymessageattime (intlong  uptimemillis) {    =  Message.obtain ();     = what ;     return sendmessageattime (msg, uptimemillis);}
 Public BooleanSendmessageattime (Message msg,LongUptimemillis) {MessageQueue Queue=Mqueue; if(Queue = =NULL) {runtimeexception e=NewRuntimeException ( This+ "Sendmessageattime () called with no Mqueue"); LOG.W ("Looper", E.getmessage (), E); return false; }    returnenqueuemessage (Queue, MSG, uptimemillis);}

The difference between the two is that the parameter type is different, the instance object passed by the Post method implements the Runnable interface, and then internally through the Getpostmessage method, it is converted to a message, which is finally emitted by the Send method. The Send method passes in an instance object that is of type message and, in the implementation, presses the message into MessageQueue.

Private Static Message Getpostmessage (Runnable r) {    = message.obtain ();     = R;     return m;}

      After the message is pressed into MessageQueue via handler, Looper is polled and referred to the target handler of the message. Handler will first distribute the message. The first is to determine whether the callback processing interface of message callback is NULL, NOT NULL to call the callback for processing, or not to determine whether handler's callback interface Mcallback is null. is not NULL, the callback is called for processing, and if all of the above callback are null, the Handlemessage method is called to process.

 Public void DispatchMessage (Message msg) {    ifnull) {        handlecallback (msg);     Else {        ifnull) {            if  (Mcallback.handlemessage ( msg) {                return;            }        }        Handlemessage (msg);}    }

The Handlemessage method must be implemented in a subclass of handler. That is, the specific processing of the message is implemented by the application software.

/***/publicvoid  handlemessage (Message msg) {}

Go back to activity (Fragment) and implement the Handlemessage method in the subclass of handler. Here we need to pay attention to a memory leak problem, compare the following two implementation methods, the first directly define the implementation of handler, the second through the static inner class inherits handler, defines an instance of the inheriting class.

New Handler () {                @Override    publicvoid  handlemessage (Message msg) {          Super. Handlemessage (msg);                     // method of calling activity based on MSG     }};
Static classMyHandlerextendsHandler {weakreference<DemoActivity>mactivity;  PublicMyHandler (demoactivity demoactivity) {mactivity=NewWeakreference<demoactivity>(demoactivity); } @Override Public voidhandlemessage (Message msg) {Super. Handlemessage (msg); Demoactivity theactivity=Mactivity.get (); //method of calling theactivity based on MSG}

Not mealy, which directly explains why the first approach causes memory leaks, and the second does not.

In the first way, Mhandler is instantiated by an anonymous inner class, in Java, where the inner class holds a reference to the outer class strongly (the method in the Handlemessage method can invoke the activity directly), After the external activity calls the OnDestroy () method, if Handler's MessageQueue still has an unhandled message, the activity cannot be reclaimed by the system because the handler holds the activity reference. This can cause a memory leak.

In the second way, the first inheritance handler defines the static inner class, because MyHandler is a static class, even if it is defined within the activity, there is no logical connection with the activity, that is, the external activity is not a reference; second, inside the static class, Defines weak references to external activity, which are prioritized by the system when system resources are tight. Finally, in the Handlemessage () method, a reference to the external activity is obtained through the Get method of the WeakReference , and if the weak reference has been reclaimed, the Get method returns NULL.

structGcspec {/*If True, only the application heap is threatened.*/  BOOLispartial; /*If True, the trace is a run concurrently with the mutator.*/  BOOLisconcurrent; /*toggles for the soft reference clearing policy.*/  BOOLDopreserve; /*A name for this garbage collection mode.*/  Const Char*reason;};

This code is defined in Dalvik/vm/alloc/heap.h, where dopreserve is true, indicating that the object referenced by the soft reference is not reclaimed during GC execution, and false to indicate that during GC execution, Reclaims the object referenced by the soft reference.

Finally, in the process of using handler, it is also important to note that it is mentioned in the previous method list diagram. To prevent activity from calling OnDestroy, a message is still present in the MessageQueue of handler, and the Removecallbacksandmessages () method is generally called in OnDestroy.

@Override protected void OnDestroy () {    super. OnDestroy ();     // Empty Message Queue    Myhandler.removecallbacksandmessages (null);}
 Public Final void removecallbacksandmessages (Object token) {    mqueue.removecallbacksandmessages (this, token);}

The Removecallbacksandmessages () method removes the message sent by post sent by callback and send by obj as token, removing all callback and messages when token is null.

Properties and operation of 1.2 MessageQueue

MessageQueue, Message Queuing, whose properties are similar to regular queues, including the queue, the team, and so on, here is a brief introduction to the implementation of MessageQueue.

First, the work of MessageQueue new queue is implemented by calling the local method Nativeinit in its constructor. Nativeinit creates the Nativemessagequeue object and assigns a value to the MessageQueue member variable mptr. MPTR is the int type data that represents the Nativemessagequeue memory pointer.

MessageQueue (boolean  quitallowed) {    = quitallowed;     = nativeinit ();}

Second, the message is queued for implementation through the Enqueuemessage method. First check that the message meets the queued requirements (whether it is in use, target handler is null), and then completes the queue by setting a pointer to Prev.next = MSG queues.

Boolean Long When );

Again, the team is done by the next () method. Related to the synchronization, lock and other issues, here is not detailed deployment.

Again, the deletion element has two implementations. That is, through p.callback = = r and P.what = = What to do message recognition.

void int What , Object object); void removemessages (Handler H, Runnable r, Object object);

Finally, the destruction of the queue is done with local functions, just as the queue is created. The passed-in parameter is a MessageQueue memory pointer.

Private native Static void Nativedestroy (int ptr);
How the 1.3 looper works

Looper is the key to thread communication, and it is precisely because of looper that the whole thread communication mechanism really realizes "pass".

In the application development process, when the main thread needs to pass the message to the user custom thread, the handler is defined in the custom thread for message processing, and the prepare () method and the loop () method of Looper are called respectively before and after the handler implementation. The approximate implementation is as follows:

 new  Thread (new   Runnable () { private   Handler Mhandler; @Override  public  void   run () {looper.prepare ();            Mhandler  = new   Handler () {@Override  public  void   Handlemessage (Message msg) { super  .handlemessage (msg);        }        };    Looper.loop (); }});

The prepare () method and the loop () method are highlighted here, and it is not recommended to define anonymous threads in the actual project.

Private Static void Prepare (boolean  quitallowed) {    ifnull) {          ThrowNew runtimeexception ("Only one Looper could be created per thread");    }    Sthreadlocal.set (new  Looper (quitallowed));}

It can be seen that the focus of the Prepare method is the sthreadlocal variable, what is the sthreadlocal variable?

// Sthreadlocal.get () would return null unless you ' ve called prepare (). Static Final New Threadlocal<looper> ();

The threadlocal implements thread-local storage. Simply take a look at its class annotation document, Threadlocal is a special global variable that is globally stored in its own thread-related data, while other threads cannot access it.

 /**   * Implements a thread-local storage, that is, a variable for which each thread * have its own value. All threads share the same {  @code   ThreadLocal} object, * But all sees a different value when accessing it, and changes made by one * thread does not affect t He other threads. The implementation supports * {  @code   null} Values. * *   @see   Java.lang.Thread *   @author   Bob Lee  */  public  class  threadlocal<t>  {}  

Back in the Prepare method, Sthreadlocal adds a Looper object for the current thread. And the Prepare method can only be called once, otherwise a run-time exception is thrown.

After initialization, how does the post and send methods ensure that messages are delivered to the MessageQueue held by Looper handler? In fact, MessageQueue is the bridge between handler and Looper. In the previous handler section, the handler initialization method is mentioned, handler Mlooper object is obtained through Looper static method Mylooper (), and Mylooper () is by calling Sthreadlocal.get () To get, that is, Handler Mlooper is the Looper object of the current thread, handler Mqueue is mlooper.mqueue.

= Looper.mylooper (); if NULL ) {   thrownew  runtimeexception (        "Can ' t create handler inside thread that Have not called Looper.prepare () "= mlooper.mqueue;
 Public Static Looper Mylooper () {    return  sthreadlocal.get ();}

Android thread Management--thread communication

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.