Android知识Android开发Android技术知识

Handler简单分析-runOnUiThread,view.p

2017-04-23  本文已影响254人  姜康

网上有很多关于Handler的帖子,但是看了那么多,不自己亲自分析一下,还是虚得很

哪些地方用到了Handler?

runOnUiThread(Runnable action)   

我们在Activity中写处理逻辑的时候,经常会用到这个方法,用来保证代码在UI线程中执行。
来看看它是怎么实现的:

 /**
     * Runs the specified action on the UI thread. If the current thread is the UI
     * thread, then the action is executed immediately. If the current thread is
     * not the UI thread, the action is posted to the event queue of the UI thread.
     *
     * @param action the action to run on the UI thread
     */
    public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }

可以看到,如果当前线程是UI线程,则调用Handler的post方法。否则直接运行。
那么就来看看Handler的post方法:

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

往下:

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

再往下:

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

可以看到最后调用的方法是 sendMessageAtTime(Message msg, long uptimeMillis),该方法将消息放入MessageQueque中。

send系列

其实上面这几个常用的方法最终也是调用的sendMessageAtTime(Message msg, long uptimeMillis)方法。

View中的post方法
它的作用是在UI线程中执行代码逻辑。

废话不多说,看源码:

/**
     * <p>Causes the Runnable to be added to the message queue.
     * The runnable will be run on the user interface thread.</p>
     *
     * @param action The Runnable that will be executed.
     *
     * @return Returns true if the Runnable was successfully placed in to the
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.
     *
     * @see #postDelayed
     * @see #removeCallbacks
     */
    public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            return attachInfo.mHandler.post(action);
        }

        // Postpone the runnable until we know on which thread it needs to run.
        // Assume that the runnable will be successfully placed after attach.
        getRunQueue().post(action);
        return true;
    }

View的显示都依赖于Window,而AttachInfo可以看作是View和Window的桥梁。
这里可以看到如果attachInfo不为空,则会调用Handler的post方法,否则调用getRunQueue().post(action);
这里来看一下getRunQueue().post(action)的实现

/**
     * Returns the queue of runnable for this view.
     *
     * @return the queue of runnables for this view
     */
    private HandlerActionQueue getRunQueue() {
        if (mRunQueue == null) {
            mRunQueue = new HandlerActionQueue();
        }
        return mRunQueue;
    }

好的,到HandlerActionQueue中看看去:

public void post(Runnable action) {
        postDelayed(action, 0);
    }

    public void postDelayed(Runnable action, long delayMillis) {
        final HandlerAction handlerAction = new HandlerAction(action, delayMillis);

        synchronized (this) {
            if (mActions == null) {
                mActions = new HandlerAction[4];
            }
            mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
            mCount++;
        }
    }

public void executeActions(Handler handler) {
        synchronized (this) {
            final HandlerAction[] actions = mActions;
            for (int i = 0, count = mCount; i < count; i++) {
                final HandlerAction handlerAction = actions[i];
                handler.postDelayed(handlerAction.action, handlerAction.delay);
            }

            mActions = null;
            mCount = 0;
        }
    }

可以看到实际上是把线程放入了 HandlerAction数组中,然后在view中会调用
executeActions方法传入handler,然后调用它的postDelayed方法。

上一篇 下一篇

猜你喜欢

热点阅读