Handler, loiter, HandlerThread analysis, handlerthreadloiter

Source: Internet
Author: User

Handler, loiter, HandlerThread analysis, handlerthreadloiter

Handler must have been used in the process of writing Android code, especially when the blocking operation thread is used to update the UI thread. Handler is used properly to prevent many multi-thread exceptions.

Logoff is also known to everyone, but the logoff is generally not used to write application code. However, the key to the actual Handler's Message processing lies in logoff.

The following is a summary after I have read the relevant chapter <in-depth understanding of Android>.

Handler

Let's take a look at the Handler constructor.

 

public Handler() {        this(null, false);    }public Handler(Looper looper) {        this(looper, null, false);    }public Handler(Callback callback, boolean async) {        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 leaks might occur: " +                    klass.getCanonicalName());            }        }        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;    }

 

Focus on the two member variables mQueue and mloue of Handler.

Mlogoff can be passed in from the constructor. If the constructor does not pass in, The logoff of the current thread will be taken directly: mlogoff = logoff. mylogoff ();

MQueue is mLooper. mQueue.

 

Insert Message into Message Queue

 

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

 

The above two methods insert messages into the Message queue.

It can be seen that the Message is inserted into the mQueue, which is actually mLooper. mQueue.

Each message.tar get = this, that is, the target is set to the current Handler instance.

At this point, we need to see what logoff is doing.

 

Logoff

This is a standard example of logoff.

 

class LooperThread extends Thread {        public Handler mHandler;        public void run() {        Looper.prepare();                ......        Looper.loop();       }}

 

Let's take a look at the implementation of lorule. prepare () and lorule. loop.

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));    }public static Looper myLooper() {        return sThreadLocal.get();    }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 this thread is that of the local process,        // and keep track of what that 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 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.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            // 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.recycleUnchecked();        }    }

The prepare () method sets a logoff instance for sThreadLocal.

SThreadLocal is the Thread Local Variables and the Thread Local variable.

Every time you call the mylogoff () method, you can return the logoff instance set in prepare.

 

There is a conspicuous infinite For loop in the logoff () method, which is used to continuously process the Message in messageQueue.

The message.tar get. dispatchMessage (msg) method will be used at the end. As mentioned earlier, the target is a handler instance. Let's take a look at the implementation of the handler. dispatchMessage () method.

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

The implementation is very simple. If callback is not empty, handleCallback (msg) is used to process the message.

In most cases, callback is not passed when Handler is instantiated, so it will go to handler. handleMessage () method. those who have used Handler in this method are no longer familiar with it.

This is the working principle of Handler and logoff. The implementation of message queue is logoff, and Handler is more like a helper class.

 

HandlerThread

In most cases, Handler is used to process UI interface updates. In this case, we need to ensure that the Logoff of handler is the Logoff of the UI thread.

You only need to instantiate Handler in this way to ensure that the Message is processed in the UI thread: Handler handler Handler = new Handler (Looper. getMainLooper ());

But when we don't want Handler to process the Message in the UI thread, we need to create a thread and pass the Logoff of the thread to Handler for instantiation.

Maybe we will write the following similar code (sample code reference <in-depth understanding of Android>)

Class LooperThread extends Thread {public Looper myLooper = null; // defines a public Member myLooper. The initial value is null. Public void run () {// assume that run executes logoff in thread 2. prepare (); // mylogoff must be assigned with mylogoff = logoff in this thread. mylogoff (); logoff. loop () ;}// the following code is executed in thread 1, and thread 2 {LooperThread lpThread = new LooperThread; lpThread is created. start (); // After the start operation, thread 2 logoff = lpThread will be created. myLooper; // <====== note // Logoff of thread2Handler and thread 2 hooks Handler thread2Handler = new Handler (logoff ); // The message sent by sendMessage will be processed by thread 2 threadHandler. sendMessage (...)}

You may have noticed it at a Glance. new Handler (logoff); The logoff may be empty.

The reason is that lpThread. mylogint may be empty when loginlogint = lpThread. mylogint is set, because lpThread has not started to execute the run () method.

How can we ensure that the logoff is not empty during handler instantiation.

Android provides us with a perfect solution, that is, HandlerThread.

Public class HandlerThread extends Thread {// Thread 1 calls getlogoff to obtain the logoff public logoff getlogoff (){...... synchronized (this) {while (isAlive () & mlove = null) {try {wait (); // If the loit has not been created for the new thread, then wait for} catch (InterruptedException e) {}} return mlotion;} // thread 2 to run its run function, which is created in the run thread. Public void run () {mTid = Process. myTid (); logoff. prepare (); // create the Looper synchronized (this) {mloed = Looper. mylogoff (); policyall (); // the notification is sent to thread 1 of logoff. At this time, the logoff has been created.} Process. setThreadPriority (mPriority); onLooperPrepared (); lorule. loop (); mTid =-1 ;}}

The HandlerThread. getLooper () method will be returned only after mLooper is assigned a value.

When handler instantiates and calls handlerThread. getLooper () method, we can ensure that the obtained Looper is not empty.

HandlerThread handlerThread = new HandlerThread();handlerThread.start();Handler handler = new Handler(handlerThread.getLooper());

 

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.