Android source code analysis-detailed explanation of Handler and logoff mechanisms

Source: Internet
Author: User

Android source code analysis-detailed explanation of Handler and logoff mechanisms

In the Android system, similar to Java applications, the applications are message-driven. Simply put, there is a message queue, we can continuously add messages to this message queue, retrieve messages from them, and process messages. In Android, Handler, logoff, and Message are mainly involved in this work.

Logoff class: a message loop is run for a thread. There is a message queue in it. Each thread can only have one logoff. Handler class: allows you to send messages to and process messages in a thread's Message queue. Message class: Message class. Example

First, we will use a simple example to learn how to use logoff and Handler, and use this example to study its working principle;
1. We will prepare for the message loop in LooperThread and create a Handler to process the message. Note that the Handler should be created after the Looper. prepare () call;

public class LooperThread extends Thread {    public Handler mHandler;    @Override    public void run() {        // TODO Auto-generated method stub        Looper.prepare();        synchronized (this) {            mHandler = new Handler() {                @Override                public void handleMessage(Message msg) {                    // TODO Auto-generated method stub                    super.handleMessage(msg);                    Log.w("LooperThread", "handleMessage::Thread id---" + getId());                }            };        }        Looper.loop();        notifyAll();    }}

2. Create a New thread in the main thread and send a message to the LooperThread through the Handler in the LooperThread;

Final LooperThread mLooperThread = new LooperThread (); mLooperThread. start (); new Thread () {@ Override public void run () {// TODO Auto-generated method stub while (mLooperThread. mHandler = null) {try {wait (); // prevents Handler from establishing} catch (InterruptedException e) {// TODO Auto-generated catch block e. printStackTrace () ;}} mLooperThread. mHandler. sendEmptyMessage (0); Log. w (TAG, "Send Message: Thread id ---" + getId ());}}. start ();

This example mainly creates a new Thread and sends messages to LooperThread in this Thread. To prevent Handler from being synchronized when a message is sent, when mHandler is null, the thread is blocked to wait. When Handler is set up, the thread is awakened. You can see the result in the log:

Logoff Analysis

From the above example, we can see that if we want to manage messages in this thread, we first need to call the lorule. prepare method. Let's take a look at this method first:

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

We can see that in the prepare method, we first judge whether the logoff has been created in the thread, and then call the set Method of ThreadLocal. ThreadLocal is a local variable class of threads in Java. It enables each thread to maintain its own independent object. Generally, ThreadLocal is used. the objects from set () to the thread are the objects used by the thread. Other threads do not need to be accessed or cannot be accessed. I will not repeat the ThreadLocal mechanism too much here.

Here we set a Looper for this thread. Next let's look at the Looper constructor:

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

We can see that in the constructor, we created a new message queue and set the current thread.

Next, we created a Handler. We analyzed the Handler for a moment. Finally, we called the logoff loop method for message loop. Let's take a look at this method:

The public static void loop () {// mylogoff () method is implemented through sThreadLocal. get () returns the loginfinal loginme = myloginme (); if (me = null) {throw new RuntimeException ("No loginexception; logint. prepare () wasn' t called on this thread. ");} final MessageQueue queue = me. mQueue; // ensure that the thread is consistent with the local process, and record this identity token Binder. clearCallingIdentity (); final long ident = Binder. clearCallingIdentity (); for (;) {Message msg = Queue. next (); // It may block if (msg = null) {// if no message exists, it indicates that the message queue has exited. return;} // This must be in a local variable, in case a UI event sets the logger Printer logging = me. mLogging; if (logging! = Null) {logging. println (">>>>> Dispatching to" + msg.tar get + "" + msg. callback + ":" + msg. what);} // distribute the message msg.tar get. dispatchMessage (msg); if (logging! = Null) {logging. println ("<Finished to" + msg.tar get + "" + msg. callback);} // ensure that the thread does not crash during delivery. 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.tar get. getClass (). getName () + "" + msg. callback + "what =" + msg. what);} msg. recycle ();}}

We can see that the loop method is mainly to retrieve messages from the message queue and distribute the messages.

To sum up, logoff's work:

Encapsulates a message queue, and uses prepare to associate logoff with the thread that calls the prepare method. uses the loop function to send messages to Handler for analysis.

Now that we know how logoff works, let's take a look at how to send messages. First, let's take a look at its construction method,

    public Handler(Callback callback, boolean async) {        ......        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;    }

The non-parameter constructor calls the this (null, flase) constructor. We can see that there is a logoff in the Handler member variable. First, we obtain the Logoff of the thread currently created for Handler, in addition, we can see that a message queue is saved in Handler and finally points to the logoff message queue.

After the sendMessage method is called, a message is sent to logoff. Let's see how the message is transmitted in this method. The sendMessage method will eventually call the sendMessageAtTime method:

    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);    }    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);    }

As you can see, the sendMessage method finally calls the queue. enqueueMessage method to add the message to the message queue in the logoff.

As shown above, the dispatchMessage method is called for sending messages:

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

As you can see, dispatchMessage sets a priority mechanism for message processing:

If the Message comes with a Callback, it is handed over to the Callback processing of the Message; if the Handler sets a Callback, it is handed over to the Handler's Callback processing; if neither is available, the handleMessage method is called for processing. Synchronization between Handler and logoff

In the above example, we can find that Handler and Looper have synchronization problems. If Handler is not created in LooperThread, a message is sent in the second thread, this will cause a null pointer exception. As mentioned above, I have referred to HandlerThread in Android and used the wait/policyall method to solve this problem. We can use HandlerThread in actual use.

    final HandlerThread mHandlerThread = new HandlerThread("LooperThread");    mHandlerThread.start();    final Handler mHandler = new Handler(mHandlerThread.getLooper()){        @Override        public void handleMessage(Message msg) {            // TODO Auto-generated method stub            super.handleMessage(msg);            Log.w("LooperThread", "handleMessage::Thread id---" + mHandlerThread.getId());        }    };    new Thread() {        @Override        public void run() {            // TODO Auto-generated method stub            mHandler.sendEmptyMessage(0);            Log.w(TAG, "Send Message::Thread id ---" + getId());        }    }.start();

Let's take a look at the source code of HandlerThread:

    @Override    public void run() {        mTid = Process.myTid();        Looper.prepare();        synchronized (this) {            mLooper = Looper.myLooper();            notifyAll();        }        Process.setThreadPriority(mPriority);        onLooperPrepared();        Looper.loop();        mTid = -1;    }    public Looper getLooper() {        if (!isAlive()) {            return null;        }        // If the thread has been started, wait until the looper has been created.        synchronized (this) {            while (isAlive() && mLooper == null) {                try {                    wait();                } catch (InterruptedException e) {                }            }        }        return mLooper;    }

We can see that this idea is consistent with what we used in the previous example.

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.