[Reprint] from Handler.post (Runnable R), Handler.sendemptymessage () comb Android message mechanism (as well as Handler memory leaks)

Source: Internet
Author: User

Handler

Every beginner Android development is not open handler this "Kan", why is it a hurdle, first of all, this is the essence of Android architecture, and then most people are aware of it but do not know why. Today saw Handler.post this method after decided to turn over the source code to comb the handler implementation mechanism.

Updating the UI asynchronously

First, a must-have-back formula "the main thread does not do time-consuming operation, the child thread does not update the UI", this rule should be a beginner must know, how to solve the problem in the formula, this time handler appear in front of us (Asynctask also line, However, in essence, the handler package), a classic common code (ignoring the memory leak here, we will say later):

First create a new handler in the activity:

private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 0: mTestTV.setText("This is handleMessage");//更新UI break; } } };

Then send the message in the child thread:

new Thread(new Runnable() {            @Override            public void run() { try { Thread.sleep(1000);//在子线程有一段耗时操作,比如请求网络 mHandler.sendEmptyMessage(0); } catch (InterruptedException e) { e.printStackTrace(); } } }).start();

This completes the asynchronous update UI at the main thread after the time-consuming operation of the sub-thread, but does not use the header post, and we'll look at the post version:

Private Handler Mhandler;Global variables@OverrideProtectedvoidoncreate (Bundle savedinstancestate) {Mhandler = new Handler (); Span class= "Hljs-keyword" >new Thread (new Runnable () {@ Override public void run () {try {thread.sleep (1000); new Runnable () {@ Override public void run () { Mtesttv.settext ( "This is post");  Update UI}}); } catch (interruptedexception e) {e.printstacktrace ();}}). Start ();}                 

From the surface, to the post method to pass a runnable, like open a sub-thread, but in the child line thread can not update the UI Ah, then the question comes, this is how a situation? With this doubt, to turn over the source of handler:

Let's take a look at what normal sendemptymessage looks like:

public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); }
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); }

Encapsulates the parameters we passed in as a message and then calls Sendmessagedelayed:

public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }

Call Sendmessageattime again:

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

OK, let's look at Post again ():

public final boolean post(Runnable r)    {       return sendMessageDelayed(getPostMessage(r), 0);//getPostMessage方法是两种发送消息的不同之处 }

The method is only one sentence, the internal implementation and the ordinary SendMessage is the same, but only a little different, that is getpostmessage (r) This method:

private static Message getPostMessage(Runnable r) {        Message m = Message.obtain();        m.callback = r;        return m;    }

This method we found is also the parameters we passed into the package into a message, but this time is M.callback = R, just a msg.what=what, as for the message of these properties will not look at the

Android messaging mechanism

See here, we just know that the post and SendMessage principle are encapsulated into a message, but still do not know what the whole mechanism of handler look like, continue to explore.

Just saw those two methods to finally call the sendmessageattime

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

This method calls the Enqueuemessageagain, see the name should be added to the message queue meaning, click to see:

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

Masynchronous this async-related first, continue to pass the arguments to the Enqueuemessage method of the queue, as for the value of the target of the msg we look back, Now continue into the MessageQueue class of the Enqueuemessage method, the method is longer, and we look at the key lines:

Message prev;for (;;) {    prev = p;    p = p.next;    if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; }}msg.next = p; // invariant: p == prev.nextprev.next = msg;

Sure enough, as the method name says, an infinite loop adds the message to the message queue (in the form of a list), but there is a hold on it, how does the message get it out?

Looking at the MessageQueue method, we found next (), the code is too long, do not repeat, we know it is used to get the message out of the line. But where is this method called, not in the handler, we find the key Looper , I call him a ring Messenger , specifically responsible for getting messages from the message queue, the key code is as follows:

for (;;) {     Message msg = queue.next(); // might block     ...     msg.target.dispatchMessage(msg);     ...     msg.recycleUnchecked();}

Simple and clear, we see what we just said Msg.target, just in handler in the assignment of msg.target=this, so we look at the DispatchMessage in handler:

public void dispatchMessage(Message msg) {        if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
    1. MSG callback is not empty, call the handlecallback method (message.callback.run ())
    2. Mcallback NOT NULL, call mcallback.handlemessage (msg)
    3. Finally, if all else is empty, execute handler's own handlemessage (msg) method

MSG callback should have thought of what it is, we pass Handler.post (Runnable R) into the Runnable of the Run method, here to mention the Java Foundation, The Run method of a direct call thread is equivalent to calling a method in a normal class, or executing on the current thread, and does not open a new thread.

So here we solve the confusion, why we have a runnable in post or we can update the UIin the main thread.

Keep looking at the mcallbackof the case where the fruit msg.callback is empty, this should look at the construction method:

1.PublicHandler () {ThisNullFALSE); }2.PublicHandler (Callback Callback) {This (callback,FALSE); }3.PublicHandler (Looper Looper) {This (Looper,NullFALSE); }4.PublicHandler (Looper Looper, Callback Callback) {This (Looper, callback,FALSE); }5.PublicHandler (BooleanAsync) {ThisNullAsync); }6.PublicHandler (Callback Callback, BooleanAsync) {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 leak s 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;} 7.public Handler (Looper Looper, Callback Callback, Boolean async) {mlooper = Looper; mqueue = looper.mqueue; mcallback = callb Ack masynchronous = async;}           

The specific implementation is only the last two, already know how the mcallback , in the construction method passed in the line.

Finally, if both callbacks are empty, execute handler's own Handlemessage (msg) method, which is the Handlemessage method that we know about the new handler rewrite.

Looper

See here is a doubt, that is we in the new handler when we did not pass any parameters, and there is no way to show the call Looper about the method, the creation of Looper and the method call where it? Actually these things Android itself has done for us, in the program entrance Activitythread The main method inside we can find:

 public static void main(String[] args) {    ...    Looper.prepareMainLooper();    ...    Looper.loop();    ...

Summarize

I've probably combed the handler message mechanism, and the difference between the Post method and our usual SendMessage method. To summarize, it mainly involves four classes of Handler, Message, MessageQueue, Looper:

Create a new Handler, send a message via SendMessage or post,Handler call sendmessageattime to give MessageQueue

The messagequeue.enqueuemessage method places a Message into a queue as a list

The loop method of the Looper loops calls Messagequeue.next () to take out the message and calls the Handler DispatchMessage to process messages

In DispatchMessage , the msg.callback, Mcallback , or the post method or the constructor method, respectively, are judged not to be empty to execute their callbacks. If both are empty, perform the handlemessageof our most commonly used overrides.

Finally, talk about the memory leak problem of handler

Take a look at our new handler code:

private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            ...        }    };

The handler object implicitly holds a reference to the activity when using an inner class (including an anonymous class) to create the handler.

Handler usually comes along with a time-consuming background thread that sends a message to update the UI after the task has finished executing. However, if the user shuts down the activity during a network request, and normally the activity is no longer used, it may be reclaimed during GC checking, but since the thread has not finished executing, the thread holds the handler reference (otherwise how does it send a message to handler?). ), this handler also holds the activity reference, which causes the activity to not be recycled (that is, memory leaks) until the network request is over.

In addition, if the Handler postdelayed () method is executed, there will be a MessageQueue, message, Handler, and Activity before the set delay arrives. Chain, which causes your activity to be held in a reference and cannot be recycled.

One workaround, use weak references:

static Span class= "Hljs-class" >class myhandler extends handler {WeakReference<Activity > mactivityreference; MyHandler (activity activity) {mactivityreference= new weakreference<activity> ( activity); } @Override public void handlemessage (Message msg) {final activity activity = mactivityreference.get (); if (activity! = null) {Mimageview.setimagebitmap (MBITMAP);}}} 

Reprinted from: http://blog.csdn.net/ly502541243/article/details/52062179/

[reprint] from Handler.post (Runnable R), Handler.sendemptymessage () comb Android's message mechanism (and Handler memory leaks)

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.