Using handler to implement message distribution mechanism in Android (i)

Source: Internet
Author: User

In the previous article, we talked about the method of calling handler in the SendMessage, and eventually we would go into a way called Sendmessageattime, as follows:

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

Here we see variables and methods such as MessageQueue and Enqueuemessage, and we can imagine that in the mechanism of handler implementation there must be a message queue, and it holds the numerous message objects we create.

From here, we will begin to explore some of the implementation mechanisms hidden behind handler objects that we want to know.

First, we start with the creation of handler, in the previous article, we created it by means of new handler, the code is as follows:

    Private Handler Mhandler = new Handler () {public        void Handlemessage (Message msg) {            switch (msg.what) {case            M Sg_id_1:                log.v ("Test", "Toast called from Handler.sendmessage ()");                break;            Case msg_id_2:                string str = (string) msg.obj;                LOG.V ("Test", str);                Break;}}    ;

Obviously, we're going to take a look at the handler constructor, as follows:

    Public Handler () {This (null, false);    } public Handler (Callback Callback) {This (Callback, false);    } public Handler (Looper Looper) {This (Looper, NULL, FALSE);    } public Handler (Looper Looper, Callback Callback) {This (Looper, Callback, false);    } public Handler (Boolean async) {This (null, async); } public Handler (Callback Callback, Boolean async) {if (Find_potential_leaks) {final class<? ext            Ends Handler> Klass = GetClass (); if (Klass.isanonymousclass () | | klass.ismemberclass () | | klass.islocalclass ()) && (Klass.getmo Difiers () & 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;        } public Handler (Looper Looper, Callback Callback, Boolean async) {mlooper = Looper;        Mqueue = Looper.mqueue;        Mcallback = callback;    masynchronous = async; }

We can see that the real implementation of the constructor, actually only the following two, as follows:

    Public Handler (Callback Callback, Boolean async) {        ...    }        Public Handler (Looper Looper, Callback Callback, Boolean async) {        ...    }

The difference between the two is whether there are parameter looper, and Looper is a thread-related object.

What are thread-related variables? is an object that cannot be shared between threads, only objects that are in effect within this thread.

So what is the role of the Looper object?

From my own understanding, the Looper class is the encapsulation of MessageQueue, and it mainly does two things:

1) constructs the Looper object, initializes the MessageQueue, and we can see from its constructor:

    Private Looper (Boolean quitallowed) {        mqueue = new MessageQueue (quitallowed);        Mthread = Thread.CurrentThread ();    }


Obviously, MessageQueue was initialized when the Looper was created.

We also note that this constructor is private, and it is called by the Looper.prepare method, as follows:

    public static void Prepare () {        prepare (true);    }    private static void Prepare (Boolean quitallowed) {        if (sthreadlocal.get () = null) {            throw new RuntimeException (" Only one Looper could be created per thread ");        Sthreadlocal.set (New Looper (quitallowed));    }

As you can see, when the Loop object is created, it is placed into the threadlocal variable, and threadlocal is the thread local variable, which illustrates a feature about Looper:

There can be only one Looper object in each thread.

2) Call the Loop () method to loop through the message with the following code:

    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;       ....        for (;;) {            Message msg = Queue.next ();//might block            if (msg = = null) {                //No message indicates that the message Queu E is quitting.                return;            }           ...            Msg.target.dispatchMessage (msg);           ....            Msg.recycle ();        }    }

From the above code, we can see that in an infinite loop, the message is obtained from the MessageQueue, then the message is processed through the Msg.target.dispatchMessage (msg) method call, and the message is finally recycled.

Here, we do not care about the DispatchMessage method, we first run the problem, look at the Recycle method inside what to do, as follows:

    private static Message SPool;    private static int spoolsize = 0;    private static final int max_pool_size =;    /**     * Return A new Message instance from the global pool. allows us to     * Avoid allocating new objects in many cases.     */public    static Message obtain () {        synchronized (spoolsync) {            if (sPool! = null) {                Message m = spool;
   spool = M.next;                M.next = null;                spoolsize--;                return m;            }        }        return new Message ();        public void Recycle () {        clearforrecycle ();        Synchronized (spoolsync) {            if (Spoolsize < max_pool_size) {                next = SPool;                SPool = this;                spoolsize++;}}}    

From the above code, we can see that the message object itself has a next field pointing to another message, that is, a list of messages can be chained together, into a list of message pool spool.

And here, when the Recycle method is called, the current message object is clearforrecycle, then added to the spool's head, and when we pass the obtain method of the message, we actually take it from the spool. Out an empty message object.

Believe to see here, we understand the previous article I said, why is it recommended that you use the Message.obtain method to get the message object.

Next, let's get back to the chase.

From the above about the creation of handler and the description of Looper, we can draw such a conclusion:

In each thread, if we were to create handler, then there must be a Looper object in this thread, and this Looper object encapsulates a MessageQueue object to manage the message.

So, if we're going to use handler in a new thread, we have to create a Looper object for this thread by calling the Loop.prepare () method, and the official code is as follows:

  Class Looperthread extends Thread {public      Handler Mhandler;        public void Run () {          looper.prepare ();            Mhandler = new Handler () {public              void Handlemessage (Message msg) {                  //process incoming messages here              }          };            Looper.loop ();      }  }

Of course, only the theory is not, we still have to use an example to see the specific effect, as follows:

public class Mainactivity extends Actionbaractivity {private static final int msg_id_1 = 1;    private static final int msg_id_2 = 2;        Class Looperthread extends Thread {public Handler mhandler;                public void Run () {looper.prepare (); Mhandler = new Handler () {public void Handlemessage (Message msg) {Log.                    V ("Test", "Id of Looperthread:" + thread.currentthread (). GetId ()); Switch (msg.what) {case MSG_ID_1:LOG.V ("Test", "Toast called from Handler.send                        Message () ");                    Break                        Case msg_id_2:string str = (String) msg.obj;                        LOG.V ("Test", str);                    Break            }                }            };        Looper.loop (); }} protected void OnCreate (Bundle savedinstancestate) {super.oncreate (SavedinstaNcestate);                LOG.V ("Test", "Id of Mainthread:" + thread.currentthread (). GetId ());        Looperthread looperthread = new Looperthread ();                Looperthread.start ();        while (Looperthread.mhandler = = null) {} Message message = Message.obtain ();        Message.what = msg_id_1;        LooperThread.mHandler.sendMessage (message);        Message MSG2 = Message.obtain ();        Msg2.obj = "I ' m String from Message 2";        Msg2.what = msg_id_2;    LooperThread.mHandler.sendMessage (MSG2); }}

The corresponding results are as follows:

10-27 16:48:44.519:v/test (20837): ID of mainthread:110-27 16:48:44.529:v/test (20837): ID of looperthread:6842110-27 16:48:44.529:v/test (20837): Toast called from Handler.sendmessage () 10-27 16:48:44.529:v/test (20837): Id of Looperthread:6842110-27 16:48:44.529:v/test (20837): I ' m String from Message 2

There's actually a problem here, why do we usually go straight to creating handler objects without having to call the UI thread's looper.prepare and loops?

Of course, this is certainly necessary, but this step is done by the Android system for us, so the default main thread will not need to do these initialization.

Well, in this article, we've learned about some of the connections between threads, Looper,handler, MessageQueue, and Message, and mostly about Looper objects.

End.

Using handler to implement message distribution mechanism in Android (i)

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.