Android message handling mechanism --Handler

1. Why use Handler?

Sub-thread can not change the main UI thread, asynchronous message processing mechanism, Handler completed by switching from the child thread to the main thread, the request data perfect solution child thread, the main thread updates the UI issues

2.Handler basic principles

The main thread maintains a news columns (message queue), child thread creates a message (Message), to send the message to the message queue (message queue) by the main thread of Handler, the main thread where there is a Round Robin (looper), continuous cycle to fetch messages, checking the message in the column, there are no new messages, once found a new message, looper will be handed over to Handler objects, otherwise blocked in a wait state, this time calling themselves the Handler callback function dispatchMessage (Message msg) to update the UI or other operations.
handler principle mechanism

3.Handler combination of source code analysis

3.1 Message

Message: Message
between thread data communication unit may carry data required
to create objects: Message.obtain () - message pool (string constant pool, the pool is connected, the thread pool)
encapsulated data
public int what // id identification
public int arg1
public int arg2
public Object obj

Create a message method Message.obtain ()

  	private static final int MAX_POOL_SIZE = 50;
  	...
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

Message obtained by the message pool of objects, the maximum number of message pool 50, if not new a new object.

3.2 Handler Processor

Message Handler processor is also responsible for sending messages and removal work
send an instant message: sendMessage (Message msg)
Send a message Delay: sendMessageDelayed (Message msg, long time )
processes the message: handleMessage (Message msg) (callback method)
message has not been treated to remove: removeMessages (int what)

Handler sendMessage method to send messages to the message queue, the final processing method will be given to enqueueMessage

 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
 		//把当前Handler对象赋值给msg的成员变量target,保证了谁发送谁处理
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

The method in the Handler object is assigned to the variable msg members of the target, to ensure who sent whom treatment. Finally, given the MessageQueue enqueueMessage () method for processing.

3.3 MessageQueue message queue

Look MessageQueue the enqueueMessage () method which in the end do what

    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                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.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

It used to store messages sent by Handler, which is of a Message when ordered by priority queue. (When representing the time to be processed)

3.4 Looper circulator

Remove Message Queue responsible for circulating inside Message processing currently required
to be processed Handler corresponding to
processed, the message to Message buffer pool for future reuse

Then the question come? When Looper take the news?
Looper is when it created?
While MessageQueue front did not say what time it was created?

We must first understand that broke out why the application could have been run before it to answer this question? The method of entry where it again?
The answer is in this class ActivityThread inside and see what all did

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

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

        ...
        Looper.loop();
        ...
    }

main method calls Looper.prepareMainLooper (), go look

public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

prepare (false) What did it?

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

sThreadLocal for data storage within the thread, sThreadLocal.set (new Looper (quitAllowed)) created Looper object constructor go look chant

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

Here again we created MessageQueue, that is to say a Looper corresponding to the position of MessageQueue, were correlated.

After creating a Looper, sMainLooper = myLooper () what they did?

public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

This time the main thread has been created in this Looper.
Back to the main method and finally executed Looper.loop (); when this method of doing it? With questions went in to look at it

    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 queue is quitting.
                return;
            }
            ...
            try {
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }   
           ...
            msg.recycleUnchecked();
        }
    }

The code is long, do not need to look at the whole, to extract the key code

final Looper me = myLooper (); to get in front of the main looper thread created
for (;;) {
the Message MSG = queue.next (); // get the message from the message queue continuously
IF (MSG == null) {
// no news of when to exit the loop.
return;
}
...
the try {
// this method is used to distribute messages to the handler processing, target specify who made it who deal with
msg.target.dispatchMessage (msg);
}
}

This is a cycle of death, which explains why the application can always run open, unless you manually quit the program, no message will return to exit the program, otherwise the message has been read, and handed out

3.5 dispatchMessage message distribution process

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

There are three ways to deal with this,

  1. handleCallback (msg);
    when the callback messages are created, processed by the message himself, for example:
	Handler handler = new Handler();
	handler.post(new Runnable() {
	    @Override
	    public void run() {
	    //UI操作
	    }
	});
  1. mCallback.handleMessage (msg)
    When the Handler has created callback (internal interface), the callback process themselves, for example:
   Handler.Callback callback = new Handler.Callback() {
       @Override
       public boolean handleMessage(Message msg) {
       		//UI操作
           return false;
       }
   };
   Handler handler = new Handler(callback);
   //子线程发送消息
   handler.sendMessage(msg);
  1. handleMessage (msg) Example:
     Handler handler = new Handler(){
          @Override
          public void handleMessage(Message msg) {
              //UI操作
          }
      };
	  //子线程发消息
	  handler.sendMessage(message);

And then attached a schematic
handler principle
left open several issues for reference?
What is the difference between the post method and a method sendMessage 1.Handler is?
2. Handler you can create in the child thread? How to create?
3. A thread can have multiple Handler, Looper, MessegeQueue it?

Published 28 original articles · won praise 1 · views 527

Guess you like

Origin blog.csdn.net/qq_40575302/article/details/104535997