• Handler的PostDelayed方法


    Handler的PostDelayed底层实现原理

    Handler的PostDelayed方法参数是一个Runnable对象。delayMillis为延迟时间,PostDelayed函数实际是调用的SendMessageDelayed方法

    public final boolean postDelayed(Runnable r, long delayMillis)
    {
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }
    

    Runnable会被getPostMessage()函数封装在Message对象的Callback属性中。

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

    SendMessageDelayed函数会调用SendMessageAtTime, SendMessageAtTime函数会计算出(当前时间+延迟时间 )这个消息需要在什么时间执行作为参数传递。

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

    SendMessageAtTime会继续调用enqueueMessage函数

    sendMessageAtTime(Message msg, long uptimeMillis)
    {
        MessageQueue queue
        enqueueMessage(queue, msg, uptimeMillis);
    }
    

    enqueueMessage将消息发送到主线程的消息队列MessageQueue中,并将发送消息的Handler对象封装到message消息对象的target字段。

    
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this; // 把发送消息的 handler对象封装到到 msg.target 属性中
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
    

    然后Looper循环器(相当于windows消息机制中的消息循环)会从MessageQueue消息队列中取出Message消息。并通过执行msg.target.dispatchMessage(msg)调用handler对象的dispathchMessage方法。

    public static void loop() {
        final Looper me = myLooper(); // 返回当前 looper
        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 (;;) { // 循环取出queue 中的msg
            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
            。。。
            final long end;
            try {
                msg.target.dispatchMessage(msg);    // 使用发送消息的 handler 分发消息
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            .....
    
            msg.recycleUnchecked();
        }
    }
    
    

    然后handler的dispathMessage方法会判断msg的类型,如果msg.callback不为NULL(也就是我们的Runnable对象),则执行handleCallback(msg)

    
    /*
    * 根据 msg 的不同类型分发消息
    */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {// 
            handleCallback(msg);// 在handler.post(runnable)或 postDelayed(runnable,1000)的时候会执行到这里
        } else {
            if (mCallback != null) { 
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    

    handleCallback会执行Message.callback.run()也就是Runnable对象的run方法。
    注意:因为new Runnable()是创建一个匿名内部类(runnable为接口类)即没名字的类,所以不创建新的线程,还在UI线程中执行run()。

  • 相关阅读:
    WEB免费打印控件推荐
    json.net 反序列化
    PHP文件显示乱码
    ASP.NET服务开启后Session丢失的解决方法
    phpmyadmin 下载
    phpMyAdmin 错误 缺少 mysqli 扩展。请检查 PHP 配置
    解决IE6IE7下li上下间距
    获取IP地址方法
    Winform中DataGridView的DataGridViewCheckBoxColumn使用方法(选中与选不中)
    IIS配置PHP5.3配置完成后FastCGI Error14001 (0x800736b1)___解决方法
  • 原文地址:https://www.cnblogs.com/revercc/p/16137828.html
Copyright © 2020-2023  润新知