Detailed explanation of Android handler mechanism flow

Detailed explanation of Android handler mechanism flow

The handler mechanism consists of the following parts:

.Handler
.Message
.MessageQueue
.Looper

Overall process introduction:

1. When the process starts,
a Looper corresponding to its own thread is created in the main method for the main thread. A MessageQueue message queue is created and held when the Looper is created. At the same time, Looper.loop () is called in the main method to perform an infinite loop to traverse the message queue held by Looper.

Second, create a handler
If created in the main thread, the handler can get the looper corresponding to the main thread and hold it. If you are creating a handler in a child thread, you need to call the looper creation method and call Looper.loop yourself. Otherwise, an error will be reported.

3. Create and send
a message. The created message encapsulates its own handler information into the message, and is finally sent to the MessageQueue message queue.

Fourth, receive the message
In Looper.loop, take the Message from the MessageQueue, and distribute the processing according to the corresponding handler information

Correspondence:
A thread Thread corresponds to a unique Looper, and the corresponding information is stored in ThreadLocal.
A Looper object holds its own MessageQueue.
In the same thread, no matter how many handlers are created, there is only one Looper and one MessageQueue.
Therefore, when the handler is created, it is bound to the corresponding thread according to Looper. Even if another thread sends a message according to the handler, it will be sent to the message queue of Looper corresponding to the handler and distributed.

Code analysis:

Next, give a simple example, and briefly analyze the original code corresponding to the main process:

private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
               
            }
        }
    };
    new Thread() {
            public void run() {
                    Message message = handler.obtainMessage();
                    message.what = 100;
                    message.obj = "测试+ : " + i;
                    handler.sendMessage(message);
            }
        }.start();

Analysis:
Handler: responsible for sending messages and receiving returned messages, source code analysis of the main process part

public class Handler {
    //主要变量
    final Looper mLooper;//与每个线程对应的looper
    final MessageQueue mQueue;//消息队列
    final Callback mCallback;//是否同步

    //构造方法
    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            ..
        }
        mLooper = Looper.myLooper();//根据当前线程信息在ThreadLocal中获取线程对应的looper
        注:
        .如果是在子线程中创建,需要调用Looper.prepare( boolean quitAllowed)
        .该方法的作用是获取调用方法的线程信息,判断当前线程是否有looper,没有则创建。
        .在ActivityThread中创建过主线程的looper

        if (mLooper == null) {
            ..
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }


//从消息对象池中取出消息
    public final Message obtainMessage()
    {
        return Message.obtain(this);
    }


//发送消息的各种方法
handler.sendMessage(message);
handler.sendMessageDelayed(
    Message msg, long delayMillis);
handler.sendMessageAtTime(
    Message msg, long uptimeMillis);
handler.sendEmptyMessage(
    int what);
handler.sendEmptyMessageDelayed(
    int what, long delayMillis);
handler.sendMessageAtFrontOfQueue(
    Message msg);
handler.sendEmptyMessageAtTime(
    int what, long uptimeMillis);

    //最终都是调用来发送
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;//将当前handler信息封装进Message
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }


//分发消息

    /**
     * 该方法在Looper中next()方法中被调用  根据msg.target来区分
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

}

Main events:

1. When calling: new Handler ():
1. In Handler: Looper.myLooper ();
Get the looper corresponding to the current thread in ThreadLocal. The looper corresponding to the main thread has been created in the main method

2. mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
take out the message queue (mQueue) in the looper. Callback object. Whether to synchronize. Encapsulated into the handler object

Second, when calling: handler.obtainMessage ():
Get the message in the message object pool.

3. When calling: sendMessage or various send methods:
finally call enqueueMessage, encapsulate the current handler object into message.target,
and call mQueue.enqueueMessage (msg, uptimeMillis) to send the message to the message queue

Message: responsible for encapsulating the message, the source code analysis of the main process part

public final class Message implements Parcelable {
    public int what;
    public int arg1;
    public int arg2;
    public Object obj;
    long when;
    Bundle data;
    Handler target;
    Runnable callback;
    Message next;
    public static final Object sPoolSync = new Object();
    private static Message sPool;
    private static int sPoolSize = 0;
    private static final int MAX_POOL_SIZE = 50;
    private static boolean gCheckRecycle = true;


    //被handler调用
    public static Message obtain(Handler h) {
        Message m = obtain();
        m.target = h;
        return m;
    }

    /**
     * 判断消息对象池中是否有消息,并从消息对象池中获取消息
     */
    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();
    }

    省略其他好多方法...

Conclusion: When using obtain (this) in the handler to get the message object in the message pool, encapsulate the current this into message.target

Looper: keep looping, get messages from the message queue, and distribute messages according to the target of the message, that is, call the dispatchMessage method of the corresponding handler. Source code analysis of the main process

    public final class Looper {
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;  // 主线程looper对象
    final MessageQueue mQueue; //消息队列
    final Thread mThread;//当前线程

    //构造方法:只有一个构造,并且创建mQueue 和给mThread 赋值
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

    //初始化,如果handler在子线程中被调用,则要先调用此方法
    public static void prepare() {
        prepare(true);
    }

    //被上面方法调用
    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            //该方法内部根据当前线程信息判断是否创建了looper对象,如果有创建,则返回对应looper对象。
            //如果没有创建,则返回空
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        //创建一个looper对象,并将当前线程和该looper绑定
        sThreadLocal.set(new Looper(quitAllowed));
    }

    //主线程在创建的时候在ActivityThread类中main方法中被调用
     创建主线程对应的looper和给当前sMainLooper赋值
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    //handler中获取looper的方法
    public static @Nullable
    Looper myLooper() {
        //该方法内部根据当前线程信息判断是否创建了looper对象,如果有创建,则返回对应looper对象。
        //如果没有创建,则返回空
        return sThreadLocal.get();
    }

    //开启loop循环查询队列,
    主线程对应的loop方法在main中被调用,如果在子线程中创建的handler,需要自己调用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;

        省略众多代码....

        for (; ; ) {
        
        //队列的next()方法中处理基本逻辑,如果有消息:返回。如果没有消息:阻塞||等待
            Message msg = queue.next(); 
            if (msg == null) {
                return;
            }
            省略众多代码.....
            try {
                msg.target.dispatchMessage(msg);//根据targer(即handler)进行分发
                ..
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            //将消息放回消息池
            msg.recycleUnchecked();
        }
    }
}

This class is responsible for doing:

1. When prepare () is called:
This method can be defined as: creating a looper corresponding to the calling thread, judging whether the called thread has a looper object, if there is an error, then creating and binding the thread and looper.

2. When the construction is called:
create a MessageQueue and assign a value to the mThread variable (current thread)

3. When myLooper () is called:
This method can be defined as obtaining the looper corresponding to the thread, judging whether the called thread has a looper object, and returning if there is, without returning null.

4. The prepareMainLooper () method is called in the main method to create the looper corresponding to the main thread.

5. The loop () method is called in main, which acts as an infinite loop to take messages from the message queue held by the current thread corresponding to the looper and distribute them according to the targer corresponding to the message.

Note: When the source code is parsed here, there is a question: why the loop of Looper in the main thread does not cause ANR
Explanation: Why does Looper.loop infinite loop not cause ANR

MessageQueue: Message queue, receive the message sent by the handler and store it in the queue, traverse the message queue in an infinite loop and return to the looper. When there is no message in the message queue, block || wait. Source code analysis of the main process

public final class MessageQueue {

    private final boolean mQuitAllowed;
    是否允许退出
    private boolean mQuitting;//是否放弃消息队列

    @SuppressWarnings("unused")
    private long mPtr;

    private native static long nativeInit();//返回一个NativeMessageQueue,具体实现过程在Nativity层

    private native static void nativeWake(long ptr);//唤醒对应线程


    //构造
    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;//是否允许退出
        mPtr = nativeInit();//返回一个NativeMessageQueue,具体实现过程在Nativity层
    }


    //该方法就是在handler中调用send系列方法最终调用的方法,将消息放入消息队列
    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {//msg.target就是发送此消息的Handler
            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;//将延迟时间封装到msg内部
            Message p = mMessages;//消息队列的第一个元素
            boolean needWake;//是否需要唤醒线程
            if (p == null || when == 0 || when < p.when) {
//如果此队列中头部元素是null(空的队列,一般是第一次),
或者此消息不是延时的消息,则此消息需要被立即处理,
此时会将这个消息作为新的头部元素,并将此消息的next指向旧的头部元素,
然后判断如果Looper获取消息的线程如果是阻塞状态则唤醒它,让它立刻去拿消息处理。

                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
//如果此消息是延时的消息,则将其添加到队列中,
原理就是链表的添加新元素,按照when,也就是延迟的时间来插入的,
延迟的时间越长,越靠后,这样就得到一条有序的延时消息链表,
取出消息的时候,延迟时间越小的,就被先获取了。插入延时消息不需要唤醒Looper线程

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

            if (needWake) {
                nativeWake(mPtr);//唤醒线程
            }
        }
        return true;
    }


    //该方法就是在Looper中被调用的方法,返回一个message,如果队列为空,则阻塞
    Message next() {
        final long ptr = mPtr;
//从注释可以看出,只有looper被放弃的时候(调用了quit方法)才返回null,
mPtr是MessageQueue的一个long型成员变量,关联的是一个在C++层的MessageQueue,
阻塞操作就是通过底层的这个MessageQueue来操作的;当队列被放弃的时候其变为0
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1;
        int nextPollTimeoutMillis = 0;
        for (; ; ) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

//阻塞方法,主要是通过native层的epoll监听文件描述符的写入事件来实现的。
//如果nextPollTimeoutMillis=-1,一直阻塞不会超时。
//如果nextPollTimeoutMillis=0,不会阻塞,立即返回。
//如果nextPollTimeoutMillis>0,最长阻塞nextPollTimeoutMillis毫秒(超时),如果期间有程序唤醒会立即返回。
            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
//msg.target == null表示此消息为消息屏障(通过postSyncBarrier方法发送来的)
//如果发现了一个消息屏障,会循环找出第一个异步消息(如果有异步消息的话),所有同步消息都将忽略(平常发送的一般都是同步消息)  
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
// 如果消息此刻还没有到时间,设置一下阻塞时间nextPollTimeoutMillis,进入下次循环的时候会调用
//nativePollOnce(ptr, nextPollTimeoutMillis)进行阻塞;

                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        //正常取出消息
                        //设置mBlocked = false代表目前没有阻塞
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    //没有消息,会一直阻塞,直到被唤醒
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }
            }
            pendingIdleHandlerCount = 0;
            nextPollTimeoutMillis = 0;
        }
    }

}

Main things to do:
MessageQueue () construction: is created when Looper is created

enqueueMessage (): A series of sender handler methods eventually return to this method in the same way, put the message into the message queue

next (): Called in Looper.loop () method to traverse the queue and return the message, blocking if there is no message in the queue

Published 60 original articles · 25 praises · 10,000+ views

Guess you like

Origin blog.csdn.net/qq_41466437/article/details/104628280