Loading...
墨滴

帅次

2021/10/27  阅读:29  主题:自定义主题1

Android 彻底掌握 Handler

Handler 介绍

Handler 允许你发送和处理与线程的 MessageQueue 关联的 Message 和 Runnable 对象。每个 Handler 实例都与一个线程和该线程的消息队列相关联。当你创建一个新的 Handler 时,它会绑定到一个 Looper。它会将消息和可运行对象传递到该 Looper 的消息队列,并在该 Looper 的线程上执行它们。

Handler 有两个主要用途:

  • 1、安排消息和可运行对象在将来的某个时间执行;
  • 2、将要在与您自己的线程不同的线程上执行的操作排入队列。

主要场景是子线程完成耗时操作的过程中,通过 Handler 向主线程发送消息 Message,用来刷新 UI 界面。 本文咱们来了解 Handler 的发送消息和处理消息的源码实现。

分析源码的时候最好是找到一个合适的切入点,Handler 源码的一个切入点就是它的默认构造器。

new Handler()

    public Handler() {
        this(nullfalse);
    }
    
    public Handler(@Nullable Callback callback, boolean async) {
        //发现泄露,初始值false,不看往下走
        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());
            }
        }
        //注释1
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        //注释2
        mQueue = mLooper.mQueue;
        //null
        mCallback = callback;
        //false
        mAsynchronous = async;
    }

在无参构造器里调用了重载的构造方法并分别传入 nullfalse。并且在构造方法中给两个全局变量赋值:mLoopermQueue。mLooper是通过 Looper 来获取。mQueue 是通过 mLooper.mQueue 获取。这说明他们都来找于 Looper 。咱们先看myLooper吧。

Looper.myLooper()

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

sThreadLocal.get()

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

可以看出,myLooper 通过一个线程本地变量中的存根,然后 mQueue 是 Looper 中的一个全局变量,类型是 MessageQueue 类型。

MessageQueue:保存要由 Looper 调度的消息列表。 Message不是直接添加到 MessageQueue 的,而是通过与 Looper 关联的 Handler 对象添加的。你可以使用 Looper.myQueue() 检索当前线程的 MessageQueue。

Looper 介绍

默认情况下,线程没有与之关联的消息循环;要创建一个,在运行循环的线程中调用 prepare ,然后循环让它处理消息,直到循环停止。

大多数与消息循环的交互是通过 Handler 类进行的。

这是一个Looper线程实现的典型例子,利用prepare和loop的分离,创建了一个初始Handler与Looper进行通信。

class LooperThread extends Thread {
       public Handler mHandler;
 
       public void run() {
           Looper.prepare();
 
           mHandler = new Handler(Looper.myLooper()) {
               public void handleMessage(Message msg) {
                   // 在这里处理传入的消息
               }
           };
 
           Looper.loop();
       }
   }

启动一个 Java 程序的入口函数是 main 方法,但是当 main 函数执行完毕之后此程序停止运行,也就是进程会自动终止。

但是当我们打开一个 Activity 之后,只要我们不按下返回键 Activity 会一直显示在屏幕上,也就是 Activity 所在进程会一直处于运行状态。实际上 Looper 内部维护一个无限循环,保证 App 进程持续进行。

Looper初始化

Activity.attach() 方法中会传入一个 ActivityThread ,ActivityThread 的 main 方法是一个新的 App 进程的入口。

ActivityThread.main()

    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        // 安装选择性系统调用拦截
        AndroidOs.install();
        // 禁止CloseGuard
        CloseGuard.setEnabled(false);
        Environment.initForCurrentUser();
        //确保 TrustedCertificateStore 查找 CA 证书的正确位置
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);
        // 调用每个进程的主线模块初始化。
        initializeMainlineModules();
        Process.setArgV0("<pre-initialized>");
        //重点:注释1
        //初始化当前进程的 Looper 对象
        Looper.prepareMainLooper();
        ...
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        ...
        //重点:注释2
        //调用 Looper 的 loop 方法开启无限循环。
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

注释1:就初始化当前进程的 Looper 对象;

注释2:调用 Looper 的 loop 方法开启无限循环(具体下面讲到)。

Looper.prepareMainLooper()

    public static void prepareMainLooper() {
        //注释1:创建一个Looper
        //下面把方法贴出来
        prepare(false);
        //加个同步方法对象锁
        synchronized (Looper.class{
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            //这个要等prepare执行完再看
            //注释1
            sMainLooper = myLooper();
        }
    }

Looper.prepare()

    private static void prepare(boolean quitAllowed) {
        //判断是否绑定过 Looper 对象
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

Looper.prepare 方法其实就是new 一个 Looper。核心之处在于将 new 出的 Looper 设置到了线程本地变量 sThreadLocal.set(looper) 中。也就是说创建的 Looper 与当前线程发生了绑定。

注意: 在创建 Looper 对象之前,会判断 sThreaLocal 中是否已经绑定过 Looper 对象,如果是则抛出异常。这行代码的目的是确保在一个线程中 Looper.prepare() 方法只能被调用 1 次。

new Looper()

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

Looper在构造方法中初始化了消息队列 MessageQueue 对象。

prepare 方法执行完之后,会在 Looper.prepareMainLooper 中处调用 myLooper() 方法,从 sThreadLocal 中取出 Looper 对象并赋值给 sMainLooper 变量。

Looper.prepare() 只能被调用1次

从上面代码可以看出Activity在被创建时已经在 Looper.prepareMainLooper()中调用了一次Looper.prepare(),我决定在onCreate()里面再调用一次Looper.prepare(),祝福我吧。 我现在我准备在MainActivity中加一行代码

@Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Looper.prepare();
    }

结果惨兮兮:

注意:

  • prepare 方法在一个线程中只能被调用 1 次
  • Looper 的构造方法在一个线程中只能被调用 1 次
  • MessageQueue 在一个线程中只会被初始化 1 次

结论:也就是说 UI 线程中只会存在 1 个 MessageQueue 对象,后续我们通过 Handler 发送的消息都会被发送到这个 MessageQueue 中。

Looper 干啥的?

总结 Looper 做的事情就是:不断从 MessageQueue 中取出 Message,然后处理 Message 中指定的任务。

回到原点,在 ActivityThread 的 main 方法中,除了调用 Looper.prepareMainLooper 初始化 Looper 对象之外,还调用了 Looper.loop 方法开启无限循环,Looper 的主要功能就是在这个循环中完成的。

Looper.loop()

    public static void loop() {
        //取出 Looper 对象并赋值给 me 
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        if (me.mInLoop) {
            Slog.w(TAG, "Loop again would have the queued messages be executed"
                    + " before this one completed.");
        }

        me.mInLoop = true;
        final MessageQueue queue = me.mQueue;
        ...
        //下面这个死循环,进去就甭想出来了。
        for (;;) {
            //注释1
            //调用 MessageQueue 的 next 方法取出 Message
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            ...
            try {
                //注释2
                //msg不为null,进行处理
                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);
                }
            }
            ...
            msg.recycleUnchecked();
        }
    }

上面代码表示loop 方法中执行了一个死循环,这也是一个 Android App 进程能够持续运行的原因。

注释1:不断地调用 MessageQueue 的 next 方法取出 Message。

注释2:如果 message 不为 null,则处进行后续处理。具体就是从 Message 中取出 target 对象,然后调用其 dispatchMessage 方法处理 Message 自身。target是谁?

Message.target

public final class Message implements Parcelable {
    ...
    @UnsupportedAppUsage
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public long when;
    /*package*/ Bundle data;
    @UnsupportedAppUsage
    /*package*/ Handler target;
    @UnsupportedAppUsage
    /*package*/ Runnable callback;
    // sometimes we store linked lists of these things
    @UnsupportedAppUsage
    /*package*/ Message next;
    /** @hide */
    public static final Object sPoolSync = new Object();
    private static Message sPool;
    private static int sPoolSize = 0;
    ...
}

查看后其实就是个Handler。那咱们再看看Handler 的 dispatchMessage 方法

Handler.dispatchMessage()

    /**
     * Handle system messages here.
     * 在这里处理系统消息。
     */

    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    /**
     * Subclasses must implement this to receive messages.
     * 子类必须实现它才能接收消息。
     */

    public void handleMessage(@NonNull Message msg) {
    }

可以看出,在 dispatchMessage 方法中会调用一个空方法 handleMessage,而这个方法也正是我们创建 Handler 时需要覆盖的方法。那么 Handler 是何时将其设置为一个 Message 的 target 的呢?

Handler.sendMessage()

Handler 有几个重载的 sendMessage 方法,但是基本都大同小异。咱使用最普通的 sendMessage 方法来分析,代码具体如下:

    public final boolean sendMessage(@NonNull Message msg) {
        return sendMessageDelayed(msg, 0);
    }

Handler.sendMessageDelayed()

    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

Handler.sendMessageAtTime()

    public boolean sendMessageAtTime(@NonNull 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);
    }

经过几层调用之后,在这里我们拿到了在 ActivityThread 的 main 方法中通过 Looper 创建的 MessageQueue。

并且最后调用 enqueueMessage 方法将 Message 插入到消息队列 MessageQueue 中。

Handler.emqueueMessage()

    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis)
 
{
        //注释
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

注释:将 Handler 自身设置为 Message的target(Handler) 对象。下来咱们看看 MessageQueue 的 enqueueMessage 方法。因此后续 Message 会调用此 Handler 的 dispatchMessage 方法来处理。

MessageQueue.enqueueMessage()

    boolean enqueueMessage(Message msg, long when) {
        //注释1,非空判断
        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.");
            }

            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();
            //注释2,从这朝下都蛮重要的
            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 {
                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;
    }

注释1:会判断msg.target == null 没有设置,则直接抛出异常;

注释2:会按照 Message 的时间 when 来有序得插入 MessageQueue 中,可以看出 MessageQueue 实际上是一个有序队列,只不过是按照 Message 的执行时间来排序。

后续就是通过 ActivityThread 的 main 方法中 Looper 创建的 MessageQueue。Looper 从 MessageQueue 中取出 Message 之后,会调用 dispatchMessage 方法进行处理。

至此 Handler 的发送消息和消息处理流程已经介绍完毕。

Handler 的 post(Runnable) 与 sendMessage(Message msg) 有什么区别

样例:

public class HandlerActivity extends ActivityBase{
    ActivityHandlerBinding binding ;
    private Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            switch (msg.what){
                case 1:
                    binding.tvTotle.setText(String.format("哈哈哈哈考了%d",msg.arg1));
                    break;
            }
            return false;
        }
    });
    @Override
    protected void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityHandlerBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        binding.btnSendMessage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message msg = new Message();
                msg.what=1;
                msg.arg1=100;
                handler.sendMessage(msg);
            }
        });
        binding.btnPost.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        binding.tvTotle.setText(String.format("哈哈哈哈考了%d",80));
                    }
                });
            }
        });
    }
}

Handler.post()

    public final boolean post(@NonNull Runnable r) {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

然后调用 getPostMessage() 传入 Runnable ,咱看看这个是干嘛的?

Handler.getPostMessage()

    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

在这个方法中你会发现getPostMessage()会将 Runnable 赋值到 Message 的 callback 变量中,返回一个Message。并调用sendMessageDelayed 方法。

Handler.sendMessage()

    public final boolean sendMessage(@NonNull Message msg) {
        return sendMessageDelayed(msg, 0);
    }

对比发现他们都调用 sendMessageDelayed() ,只不过生成的Message方式不同。 sendMessageDelayed() 上文已经讲到了就不多描述了。可以向上翻翻。

可以看出,经过几层调用之后,sendMessageDelayed 最终会调用 enqueueMessage 方法将 Message 插入到消息队列 MessageQueue 中。而这个消息队列就是我们刚才分析的在 ActivityThread 的 main 方法中通过 Looper 创建的 MessageQueue

Looper 通过 loop() 方法从 MessageQueue 中取出 Message ,Message.target(Handrle) 会调用 dispatchMessage 方法进行处理。下面咱再看看它的源码。

Handrle.dispatchMessage()

    /**
     * Handle system messages here.
     * 在这里处理系统消息。
     */

    public void dispatchMessage(@NonNull Message msg) {
        //注释1
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
        //注释2
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

咱先看看handleCallback方法

Handrle.handleCallback()

    private static void handleCallback(Message message) {
        message.callback.run();
    }

很明显,dispatchMessage 分两种情况:

注释1msg.callback != null,一般为通过 post(Runnabl) 方式,会直接执行 Runnable 的 run 方法。因此这里的 Runnable 实际上就是一个回调接口,跟线程 Thread 没有任何关系。

注释2msg.callback == null,这种一般为 sendMessage 的方式,则会调用 Handler 的 hanlerMessage 方法进行处理。

Looper.loop() 为什么不会阻塞主线程

刚才我们了解了,Looper 中的 loop 方法实际上是一个死循环。但是我们的 UI 线程却并没有被阻塞,反而还能够进行各种手势操作,这是为什么呢?在 MessageQueue 的 next 方法中.

MessageQueue.next()

    Message next() {
        // mPtr :used by native code
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }
        
        //-1:仅在第一次迭代期间
        int pendingIdleHandlerCount = -1
        //下一个Poll超时时间
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                //将当前线程中挂起的所有 Binder 命令刷新到内核驱动程序。 
                //在执行可能会阻塞很长时间的操作之前调用这会很有用,
                //以确保任何挂起的对象引用都已被释放,以防止进程持有对象的时间超过它所需的时间。
                Binder.flushPendingCommands();
            }

            //注释:重点来了。
            nativePollOnce(ptr, nextPollTimeoutMillis);

            ...
        }
    }

MessageQueue.nativePollOnce()

    private native void nativePollOnce(long ptr, int timeoutMillis)/*non-static for callbacks*/

nativePollOnce 方法是一个 native 方法,当调用此 native 方法时,主线程会释放 CPU 资源进入休眠状态,直到下条消息到达或者有事务发生,通过往 pipe 管道写端写入数据来唤醒主线程工作,这里采用的 epoll 机制。下面是关于 nativePollOnce 的部分分析,参考了nativePollOnce函数分析,感兴趣的可以去自己看看,有点懵。等我再努力努力再来看这些吧。

epoll机制:提供了Linux平台上最高效的I/O复用机制。 从调用方法上看,epoll的用法和select/poll非常类似,其主要作用就是I/O复用,即在一个地方等待多个文件句柄的I/O事件。

nativePollOnce的实现函数是android_os_MessageQueue_nativePollOnce

android_os_MessageQueue_nativePollOnce

frameworks/base/core/jni/android_os_MessageQueue.cpp

static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
        jlong ptr, jint timeoutMillis)
 
{
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
     //取出NativeMessageQueue对象,并调用它的pollOnce
    nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}

pollOnce()

frameworks/base/core/jni/android_os_MessageQueue.cpp

void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
    mPollEnv = env;
    mPollObj = pollObj;
    //重任传递到Looper的pollOnce函数
    mLooper->pollOnce(timeoutMillis);
    mPollObj = NULL;
    mPollEnv = NULL;

    if (mExceptionObj) {
        env->Throw(mExceptionObj);
        env->DeleteLocalRef(mExceptionObj);
        mExceptionObj = NULL;
    }
}

pollOnce()

system/core/libutils/include/utils/Looper.h

/**
     * 等待事件可用,以毫秒为单位可选超时。
     * 为发生事件的所有文件描述符调用回调。
     * 如果超时为零,则立即返回而不阻塞。
     * 如果超时为负,则无限期等待直到事件出现。
     * 如果之前使用wake() 唤醒轮询,则返回POLL_WAKE
     * 超时到期,没有调用回调,也没有其他文件
     * 描述符已准备就绪。
     * 如果调用了一个或多个回调,则返回 POLL_CALLBACK。
     * 如果在给定之前没有数据等待超时,则返回 POLL_TIMEOUT。
     * 如果等待过程中发生错误,则返回 POLL_ERROR。
     * 如果文件描述符有数据,则返回一个 >= 0 包含标识符的值
     * 并且它没有回调函数(这里需要调用者来处理它)。
     * 在这个(并且只有这个)情况下,outFd、outEvents 和 outData 将包含投票
     * 与 fd 关联的事件和数据,否则它们将被设置为 NULL。
     *
     * 此方法在完成调用适当的回调之前不会返回
     * 用于所有已发出信号的文件描述符。
     */

    int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);
    inline int pollOnce(int timeoutMillis) {
        //timeOutMillis参数为超时等待时间。如果为-1,则表示无限等待,直到有事件发生为止。如果值为0,则无需等待立即返回。
        return pollOnce(timeoutMillis, nullptr, nullptr, nullptr);
    }

pollOnce()

system/core/libutils/Looper.cpp

int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    //一个无限循环
    for (;;) {
        //mResponses是一个Vector,这里首先需要处理response
        while (mResponseIndex < mResponses.size()) {
            const Response& response = mResponses.itemAt(mResponseIndex++);
            int ident = response.request.ident;
            if (ident >= 0) {
                //首先处理那些没有callback的Response
                int fd = response.request.fd;
                int events = response.events;
                void* data = response.request.data;
#if DEBUG_POLL_AND_WAKE
                ALOGD("%p ~ pollOnce - returning signalled identifier %d: "
                        "fd=%d, events=0x%x, data=%p",
                        this, ident, fd, events, data)
;
#endif
                if (outFd != nullptr) *outFd 
= fd;
                if (outEvents != nullptr) *outEvents = events;
                if (outData != nullptr) *outData = data;
                //实际上,对于没有callback的Response,pollOnce只是返回它的ident,
                //并没有实际做什么处理。因为没有callback,所以系统也不知道如何处理
                return ident;
            }
        }

        if (result != 0) {
#if DEBUG_POLL_AND_WAKE
            ALOGD("%p ~ pollOnce - returning result %d"this, result)
;
#endif
            if (outFd != nullptr) *outFd 
0;
            if (outEvents != nullptr) *outEvents = 0;
            if (outData != nullptr) *outData = nullptr;
            return result;
        }
        //调用pollInner函数。注意,它在for循环内部
        result = pollInner(timeoutMillis);
    }
}

Handler 的 sendMessageDelayed 或者 postDelayed 是如何实现的

上面说到,在向 MessageQueue 队列中插入 Message 时,会根据 Message 的执行时间排序。而消息的延时处理的核心实现是在获取 Message 的阶段,接下来看下 MessageQueue 的 next 方法。

MessageQueue.next()

Message next() {
        ...
        for (;;) {
            ...
            nativePollOnce(ptr, nextPollTimeoutMillis);
            synchronized (this) {
                // 尝试检索下一条消息。 找到就返回。
                //获取系统时间。
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null) {
                    if (now < msg.when) {
                        // 下一条消息未准备好。 设置超时以在准备好时唤醒。
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // 收到一条消息。
                        //mBlocked:指示 next() 是否在 pollOnce() 中以非零超时阻塞等待。
                        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();
                        //返回 Message 
                        return msg;
                    }
                } else {
                    // 没有更多的消息。
                    nextPollTimeoutMillis = -1;
                }
            }
        }
    }

上面表示从 MessageQueue 中取出一个 Message,但是当前的系统时间小于 Message.when,因此会计算一个 timeout,目的是实现在 timeout 时间段后再将 UI 线程唤醒,因此后续处理 Message 的代码只会在 timeout 时间之后才会被 CPU 执行。

注意: 在上述代码中也能看出,如果当前系统时间大于或等于 Message.when,那么会返回 Message 给 Looper.loop()。但是这个逻辑只能保证在 when 之前消息不被处理,不能够保证一定在 when 时被处理。

小结

帅次

2021/10/27  阅读:29  主题:自定义主题1

作者介绍

帅次

公众号:帅次