美文网首页
Handler执行流程源码分析

Handler执行流程源码分析

作者: 没有了遇见 | 来源:发表于2024-03-20 15:32 被阅读0次

源码基于:API 32

核心类

  • Handler
  • Looper
  • MessageQueue
  • Message
  • HandlerCallback

1:Handler机制 是什么?

Handler 是Android提供的消息传递机制,主要用于线程间传递消息
场景:子线程处理数据UI线程更新页面
原因:Android系统中子线程不具有更新UI的能力只能通过子线程通知主线程进行更新

2:核心类

2.1 Handler

Handler 是消息的真正处理者,持有Looper对象,Looper持有MessageQueue,具有发送和接收消息的能力.

UI主线程的Looper 是在ActivityThread的main方法中创建和启动的

 public static void main(String[] args) {
        ...
      // 创建UI线程的Looper
        Looper.prepareMainLooper();
        ...

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        //启动UI线程的Looper
        Looper.loop();

    }

UI线程Looper创建和启动源码分析

  public static void prepareMainLooper() {
       //准备Looper
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            //将主线程的Looper赋值给sMainLooper
            sMainLooper = myLooper();
        }
    }


    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
       //ThreadLocal 通过 ThreadLocalMap 将主线程和Looper 绑定在一起
        sThreadLocal.set(new Looper(quitAllowed));
    }

Handler构造方法

 public Handler() {
        this(null, false);
    }
 public Handler(@Nullable Callback callback) {
        this(callback, false);
    }
  public Handler(@NonNull Looper looper) {
        this(looper, null, false);
    }
 public Handler(boolean async) {
        this(null, async);
    }
  public Handler(@Nullable Callback callback, boolean async) {...}
  public Handler( Looper looper,  Callback callback, boolean async) {... }


Looper构造方法
  private Looper(boolean quitAllowed) {
       //创建了MessageQueueu 对象
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

总结
Handler持有了Looper对象,Looper对象持有了MessageQueue,Message具有Handler的引用(handler.target 是Handler的引用),这使得Handler拥有了发送和处理消息的能力

2.2 Looper 循环的从MessageQueue中取出Message并将消息传递给Handler

Looper 轮询器 通过loop()方法中的for(;;)死循环达到轮询消息的功能

Looper构造方法
  private Looper(boolean quitAllowed) {
         //quitAllowed 是否允许退出
        //UI线程的Looper不允许退出
       //子线程的Looper默认支持退出
       //在MessageQueue 的quit()方法中会对这个参数做判断 UI线程Looper退出会抛异常
       //创建了MessageQueueu 对象
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
核心方法
  • Looper() Looper的构造方法,方法中创建了MessageQueue 队列
  • prepare()创建Looper且将Looper和Thread做绑定(ThreadLocal)
  • prepareMainLooper() 创建主线程Looper绑定主线程(不允许退出Looper)
  • getMainLooper() 获取主线程的Looper
  • loop() 开启循环消息
  • loopOnce() 轮询消息 返回true继续轮询返回false 就中断此次轮询()
    说明:
    只有调用quit()和quitSafe()方法之后 MessageQueue 的mQuitting变量未true的时候MessageQueue 的next()方法才会返回null才会执行中断循环的操作
    UI的Looper为什么不会中断
    因为UI线程的Looper创建的时候是不允许Looper的 所以主线程的的Looper不会执行quit操作
  • quit() 退出(清理所有消息)
  • quitSafe() 安全退出(时间戳大于当前时间的清理,小于当前的还会执行)

方法说明

1:构造方法:创建MessageQueue
  private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

2:prepare(): 将线程和Looper绑定在一起
    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));
    }

3:prepareMainLooper():创建UI线程的Looper ,将UI线程和Looper做绑定且给sMainLooper 赋值.
注意:
    UI线程的Looper是不可退出的(   prepare(false);)

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

4:loop()
  public static void loop() {
  //获取looper为null 抛出异常
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
   
//开启死循环处理消息
        for (;;) {
            //如果轮询不到消息就返回false 停止轮询
            if (!loopOnce(me, ident, thresholdOverride)) {
                return;
            }
        }
    }
5: loopOnce() 轮询消息 返回true继续轮询返回false 就中断此次轮询
   private static boolean loopOnce(final Looper me,
            final long ident, final int thresholdOverride) {
        Message msg = me.mQueue.next(); // might block
      //如果获取未获取到消息返回false
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return false;
        }

        ....

        try {
            //处理消息 将消息传递给Handler的回调方法
            msg.target.dispatchMessage(msg);
            if (observer != null) {
                observer.messageDispatched(token, msg);
            }
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        }
        ...
        //销毁已处理的消息
        msg.recycleUnchecked();

        return true;
    }


问题:UI线程的Looper能不能中断循环
说明:loop()只有当loopOnce()返回false的时候才会中断Loop

  public static void loop() {
  //获取looper为null 抛出异常
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
   
//开启死循环处理消息
        for (;;) {
            //1:关键代码  如果轮询不到消息就返回false 停止轮询
            if (!loopOnce(me, ident, thresholdOverride)) {
                return;
            }
        }
    }

  private static boolean loopOnce(final Looper me,
            final long ident, final int thresholdOverride) {
    //2:关键代码 判断是否轮询到消息
        Message msg = me.mQueue.next(); // might block
        if (msg == null) {
            //未轮询到消息
            return false;
        }

        '''
      
        try {
        //分发Message target 是handler本身
            msg.target.dispatchMessage(msg);
            if (observer != null) {
                observer.messageDispatched(token, msg);
            }
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } catch (Exception exception) {
            if (observer != null) {
                observer.dispatchingThrewException(token, msg, exception);
            }
            throw exception;
        } finally {
            ThreadLocalWorkSource.restore(origWorkSource);
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
    
        '''
        //清理已经处理的Message
        msg.recycleUnchecked();

        return true;
    }




MessageQueue next quit和dis代码

  Message next() {
    //5:核心代码 如果mPtr==0 也返回null 表示退出循环
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        for (;;) {
   
            synchronized (this) {      
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {     
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {          
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
             
                        msg.markInUse();
                        return msg;
                    }
                } else {  
                    nextPollTimeoutMillis = -1;
                }
                //3:关键代码 判断是否退出             
                if (mQuitting) {
        //退出
                    dispose();
                    return null;
                }

        
 
        }
    }
    
      private void dispose() {
        if (mPtr != 0) {
            nativeDestroy(mPtr);
    //4:关键代码  赋值 中断
            mPtr = 0;
        }
    }
    
       void quit(boolean safe) {
        // UI线程传递进来的是false  子线程默认都是True 所以UI线程不允许退出
        //子线程允许退出
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }
        synchronized (this) {
            if (mQuitting) {
                return;
            }
            //5:关键代码是否退出的变量值
            mQuitting = true;
            //是否安全退出
            if (safe) {
            //安全清理(不清理所有)
                removeAllFutureMessagesLocked();
            } else {
            //清理所有
                removeAllMessagesLocked();
            }
            nativeWake(mPtr);
        }
    }

总结
前提: new Looper(quitAllowed)
UI线程创建的时候配置了不允许退出循环所以不能退出循环.
子线程配置了允许退出Looper

Looper 退出流程:
1:Looper 调用quit()和quitSafe()
2:调用到了Messagequeue的quit()和quitSafe()方法,此方法中判断了是否允许退出.UI线程不允许退出 子线程允许退出.
3:允许退出后将mQuitting=true 然后移除Message数据
4:当MessageQueue 的next方法执行的时候判断了mQuitting 如果退出就返回null且mPtr=0
5:当Looper 的loop方法中loopOnce方法获取消息未null就中断了循环

2.3 MessageQueue 以队列形式(先进先出,按时间排序,msg.when)存储消息

消息队列主要用于存储和取出消息,主要用来维护消息

核心方法

  • enqueueMessage() 插入消息
  • next() next()搭配Looper loop()轮询取出消息
  • quit() 退出
  • postSyncBarrier() 发送屏障消息
  • removeSyncBarrier() 移除屏障消息
  • dispose() 如果是退出状态 改变变量
  • removeMessages() 移除消息
2.3.1 MessageQueue.enqueueMessage()

插入消息
核心:

  • msg.target == null target是handler对象,检查消息是否有线程处理
  • msg.isInUse()判断消息是否被使用
  • if (mQuitting) {} 判断 looper是否退出
  • for(;;)按时间排序
    解释说明:
    mMessages 表示当前消耗的消息
    prev 头消息
    next尾消息
    链表排序核心是 找到自己前边的消息将前边的消息的next设置成自己,将前边消息的next设置成自己的next
    排序流程
    for(;;)死循环 ,将mMessages(p) 当前处理的头消息赋值给头变量 将mMessages(p) 变量的next赋值给自身 ,然后这时判断 p.next==null 表示最后一个消息,when<p.when 表示当前需要插入的这个消息在这个消息的前边. 所以这时这个p就表示 插入消息msg的next prev的next是当前消息
boolean enqueueMessage(Message msg, long when) {
         // target是handler对象,检查消息是否有线程处理
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }

        synchronized (this) {
          //判断消息是否已经被使用
            if (msg.isInUse()) {
                throw new IllegalStateException(msg + " This message is already in use.");
            }
      //判断loop是否已退出
            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;
            //消息排序(按时间when排序)
                for (;;) {
                  // 当前消息的前一个消息
                    prev = p;
                    //核心 1:循环的把p的next赋值给p
                    p = p.next;
                    //核心2: 判断p 为null 意味着最后一个消息  when<p.when 表示 当前的时间小于这个消息的时间  这就是现在消息的位置  中断 死循环
                    if (p == null || when < p.when) {    
                      //获取当前消息的后一个消息
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                  //核心3: 给当前消息的后一个消息赋值
                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;
    }


2.3.2 MessageQueue.next() 获取下一个消息
Message next() {


        //mQuitting 退出状态的时候 mPtr=0 所以退出状态直接返回Null  loop直接退出循环
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            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;
              // msg.target == null 表示是屏障消息需要提前处理(handler.发送消息的时候在Handler的enqueueMessage中会 msg.target=this  所以target不为空且 )
                //返回屏障消息
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
//返回一般消息
                        // Got a message.
                        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 {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // 退出状态的时候直接修改  mPtr=0 直接返回Null loop退出循环
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        }
    }


2.4 Message 消息传递的消息体
2.5 Handler

相关文章

网友评论

      本文标题:Handler执行流程源码分析

      本文链接:https://www.haomeiwen.com/subject/dbwozdtx.html