介绍

在android的MessageQueue中有一个static的接口IdleHandler,这个接口用于在MessageQueue中没有可处理的Message的时候回调,这样就可以在UI线程中处理完所有的view事务之后,回调一些额外的操作而不会block UI线程。

    public static interface IdleHandler {        /**         * Called when the message queue has run out of messages and will now         * wait for more.  Return true to keep your idle handler active, false         * to have it removed.  This may be called if there are still messages         * pending in the queue, but they are all scheduled to be dispatched         * after the current time.         */        boolean queueIdle();    }
使用

接口很简单,只有一个queueIdle方法,用于在进入Idle的时候执行额外的操作,返回值是ture的话,执行完queueIdle方法之后会保留这个IdleHandler,反之则删除这个IdleHandler。

使用起来也很简单。

mHandler.getLooper().getQueue().addIdleHandler(new MessageQueue.IdleHandler() {            @Override            public boolean queueIdle() {                Log.e(TAG, "----I am idle");                return false;            }        });
源码浅析

MessageQueue的Message都是在next方法中执行的,直接看next方法

Message next() {        // Return here if the message loop has already quit and been disposed.        // This can happen if the application tries to restart a looper after quit        // which is not supported.                //-------------------第一部分---------------------------        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;                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;                }                // Process the quit message now that all pending messages have been handled.                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.                               //第一次进入,并且msg为null或者是当前的msg schedule到后面执行                if (pendingIdleHandlerCount < 0                        && (mMessages == null || now < mMessages.when)) {                    //获取当前IdleHandler的数量                    pendingIdleHandlerCount = mIdleHandlers.size();                }                 //没有需要处理的idleHandler,退出                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)];                }                //用将所有的idleHandler存入mPendingIdleHandlers                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);                }                //根据返回值,选择是否remove这个idleHandler                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;        }    }

这段代码可以分为两部分来看,第一部分用于从MessageQueue中取出可用的message,第二部分用于处理IdleHandler。我们直接从第二部分来看,首先会对当前的msg作一个判断,如果message为null或者是schedule到将来执行,那么就开始准备执行IdleHandler。所有的idleHandler放在mIdleHandlers中,将这些idleHandler转存到mPendingIdleHandlers,接下来就是迭代处理这些IdleHandler,如果返回值是false,就把这个idleHandler从mIdleHandlers中remove掉。

更多相关文章

  1. android 横竖屏切换,activity的生命周期
  2. Android时钟的widget【安卓进化三十七】
  3. android Tween Animations(动画效果-代码实现)的使用
  4. 【Android(安卓)Developers Training】 57. 在UI线程之外处理图
  5. Android获取手机屏幕宽高、状态栏高度以及字符串宽高信息的方法
  6. [置顶] android 框架
  7. android RSS解析器创建步骤
  8. 设计自己的Android(安卓)Preference
  9. 适配Android(安卓)7.0出现读取外部存储问题解决方法

随机推荐

  1. android 获取手机通讯录信息
  2. Activity背景色为透明的2种方法
  3. android activity tabhost
  4. Android软件安装文件夹
  5. Android安全问题
  6. Android——从init进程启动流程
  7. android studio开发 控件布局
  8. Launcher桌面点击&长按&拖动事件处理流程
  9. Android JNI简单实例
  10. android中context