Android understanding Looper, Handler, Message three relationships:

Handler, Looper, Message and Android are related to asynchronous message processing thread!

When your application process is created, the main thread of the application process (main thread) on the establishment of a message queue, manipulate top-level application object (such as activities, broadcast receivers, etc.) and any windows they create.

Because efficiency considerations, all of the View and Widget are not thread-safe, so the relevant action forces in the same thread, so you can avoid problems caused by multiple threads. This thread is the main thread, that the UI thread.

You can create your own thread, the main thread through a Handler object and the application of communication.

If you're a Handler and your UI thread connections, the code will be executed to process messages on the UI thread.

Communication UI thread and the new thread is achieved by post or sendMessage RELATED your new thread from the main thread and calling Handler object, given Runnable or Message Handler will message queue, and at the appropriate time It is processed.

Android operating program entry point may be considered android.app.ActivityThread class main () method:

public static final void main(String[] args) {
        // other codes...

        // 创建主线程循环
        Looper.prepareMainLooper();
        if (sMainThreadHandler == null) {
            sMainThreadHandler = new Handler();
        }

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        // other codes...

        // 进入当前线程(此时是主线程)消息循环
        Looper.loop();

        // other codes...

        thread.detach();
        // other codes...
    }

The main thread Looper class creation methods prepareMainLooper () method is designed to create the main application thread calls, the other thread should not call this method, but should call prepare () method.

1. Description: Looper create a MessageQueue (single instance), continuously removed from the message queue by a MessageQueue infinite loop and circulated by parsing, the creator is Handler.


Looper:
Key: prepare () and Loop ()
PREPARE ():

private static final ThreadLocal sThreadLocal = new ThreadLocal();  
public static final void prepare() {  
        if (sThreadLocal.get() != null) {  
            throw new RuntimeException("Only one Looper may be created per thread");  
        }  
        sThreadLocal.set(new Looper());  
}  

sThreadLocal is a ThreadLocal object that can store variable that is not shared by other threads in a thread. We can see, a Looper will put instances of the ThreadLocal, and determine whether sThreadLocal is null, or throw an exception. This ensures that only one thread in a Looper instance.

Looper constructor:

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

In the configuration process, the MessageQueue create a (message queue).

loop():

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.recycle();  
        }  
}  
public static Looper myLooper() {
      return sThreadLocal.get();
}

Method returns an instance of Looper sThreadLocal stored me is null if an exception is thrown, that is to say looper method must run after prepare method. First, get the looper instance mqueue (message queue) then enters an infinite loop, a message is continuously removed from the queue, if the message is not blocked.

If you get a message with a call msg.target.dispatchMessage (msg); the message to dispatchMessage method to deal with the target of msg. Msg handler's target is the object, the message will eventually release resources occupied.

Summarize the main role Looper:
1, with the current thread-bound to ensure that only one thread has a Looper instance, while there is only one instance of a Looper MessageQueue.
2, loop () method, from the message continuously fetch the MessageQueue, dispatchMessage target attributes to the message to process.
Well, we've got asynchronous message processing thread message queue (MessageQueue) object to send a message, this object is Handler.


Handler:
Before using the Handler, we are all initialize an instance, such as for updating the UI thread, we will directly initialized when declared or initialized in onCreate Handler instance. MQ notice it to perform a task (sendMessage), and perform the job (handleMessage) in the loop to own, the entire process is asynchronous in.

So we first look at the constructor Handler to see how it (usually to send messages in a non-UI thread) and how to send the message it sends in the child thread on the MessageQueue MessageQueue linked to.

public Handler() {  
        this(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;  
    }  

By Looper.myLooper () Gets the instance of Looper saved the current thread, then line 19 and get a hold of this Looper instance MessageQueue (Message Queue), thus ensuring on the MessageQueue instance handler associated with the example we Looper .

Then we look at the most commonly used method sendMessage

public final boolean sendMessage(Message msg)  
 {  
     return sendMessageDelayed(msg, 0);  
 }
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {  
     Message msg = Message.obtain();  
     msg.what = what;  
     return sendMessageDelayed(msg, delayMillis);  
 } 
public final boolean sendMessageDelayed(Message msg, long delayMillis)  
   {  
       if (delayMillis < 0) {  
           delayMillis = 0;  
       }  
       return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
   }  
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);  
   }  

enqueueMessage firstly assigned to meg.target is this, because the loop will be removed in the method Looper then to each msg msg.target.dispatchMessage (msg) to process the message, i.e. the handler as the current target attribute of msg. The final will call queue of enqueueMessage way to save the message queue.

It has become clear Looper will call prepare () and loop () method to save a Looper instance currently executing thread, this example will save a MessageQueue object, and then the current thread into an infinite loop and going constantly from MessageQueue in Handler reads the message sent. And then create the dispatchMessage callback method handler message of:

public void dispatchMessage(Message msg) {  
        if (msg.callback != null) { 
            // 如果message设置了callback,即runnable消息,处理callback!
            handleCallback(msg);  // 并直接调用callback的run方法!
        } else { 
            // 如果handler本身设置了callback,则执行callback 
            if (mCallback != null) {  
                if (mCallback.handleMessage(msg)) {  
                    return;  
                }  
            }// 如果message没有callback,则调用handler的钩子方法handleMessage
            handleMessage(msg);  
        }  
    }  

handleMessage (msg) is an empty method, because the final callback message by our control, we are handleMessage replication method when creating the handler, and message processing according to msg.what.

post:

mHandler.post(new Runnable()  
        {  
            @Override  
            public void run()  
            {  
                Log.e("TAG", Thread.currentThread().getName());  
                mTxt.setText("yoxi");  
            }  
        });  

Then run method can write the code to update UI, in fact, what this thread is not Runnable and create, in essence, it is to send a message:

public final boolean post(Runnable r)  
   {  
      return  sendMessageDelayed(getPostMessage(r), 0);  
   }  
private static Message getPostMessage(Runnable r) {  
      Message m = Message.obtain();  
      m.callback = r;  
      return m;  
  }  

It can be seen in getPostMessage, has been a Message object, then the object we created Runable as callback attribute assigned to this message.

Finally, and as handler.sendMessage, call sendMessageAtTime, then call the enqueueMessage method to msg.target assigned handler, eventually join the MessageQueue.


This, this process has been explained completed, to sum up:

1, first Looper.prepare () save a Looper thread in this instance, then the instance to save a MessageQueue objects, there will be only a single thread MessageQueue.
2, Looper.loop () makes the current thread enters an infinite loop, reads the message from the misconduct MessageQueue instance, and then the callback msg.target.dispatchMessage (msg) method.
3, Handler constructor will first save the current instance obtained Looper thread, in turn associated with MessageQueue.
4, Handler of sendMessage method, the target will msg assigned handler itself, the MessageQueue then added.
5, when constructing Handler instance, we will rewrite the handleMessage method, which is msg.target.dispatchMessage (msg).

发布了14 篇原创文章 · 获赞 3 · 访问量 7550

Guess you like

Origin blog.csdn.net/Xu_1215/article/details/51436151