Handler机制原理解析(二)prepare,loop,post

Handler机制原理解析(二)prepare,loop,post

上一篇已经介绍了Handler机制的原理,如果不熟悉可以看Handler机制原理解析(一)。这一篇,介绍下Handler周边的知识点。我们已经知道,要获得looper对象,必须要先执行prepare。

1,Looper.prepare

    public static void prepare() {
        prepare(true);
    }

    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));
    }

    /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     */
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

从prepareMainLooper的注释我们能看到,初始化当前线程为looper,并且标记为应用的主looper,这个主looper是Android帮忙创建的,所有不需要手动调用。我们跟踪这个方法。在ActivityThread中我们看到

public static void main(String[] args) {
   ....
   Looper.prepareMainLooper();
   ....
   Looper.loop();
   ....
}

这里我们只需知道,这个方法会在创建应用的时候调用,并且在主Activity的onCreate前已经调用了即可。至于Activity的启动流程,这里不做详述。这里我们同时也看到了另外一个方法,loop。需要注意的是,如果想在工作线程使用Handler,需要手动调用这两个方法,至于顺序,相信你一定知道。

2,post(Runnable)

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

只有这一句,接着看吧,先看getPostMessage

    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }
这里将Runnable对象r封装进Message对象了。后面就不用再分析了,因为现在已经变成了send(message),前面我们说过,最终都会调用到一个方法上。发送是相同的,可是处理是不同的。还是贴一下处理的代码吧
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

如果是发送的runnable,则会走第一个分支

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

这里也没啥,就是让其run起来。再回顾一下,无论在哪个线程post一个Runnable,最终都是会通过dispatch方法,让其run起来,而我们知道,dispatch方法是在主线程。那么View的post方法呢,应该也是封装了Handler的post吧,我们一起看看

    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;
    }

先看第一个分支,如果有attachinfo,就通过handler post出去。这个应该跟handler的方法一样。

        /**
         * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This
         * handler can be used to pump events in the UI events queue.
         */
        final Handler mHandler;

看一下Handler,果然一样。这种是view已经attach到window上了,如果没有呢?看另一个分支

    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 static <T> T[] append(T[] array, int currentSize, T element) {
        assert currentSize <= array.length;

        if (currentSize + 1 > array.length) {
            @SuppressWarnings("unchecked")
            T[] newArray = ArrayUtils.newUnpaddedArray(
                    (Class<T>) array.getClass().getComponentType(), growSize(currentSize));
            System.arraycopy(array, 0, newArray, 0, currentSize);
            array = newArray;
        }
        array[currentSize] = element;
        return array;
    }

这里能看明白,就是把handlerAction加入到数组中了(Runnable封装在handlerAction中)。这似乎也没得到执行啊。确实

,没办法,既然有post方法,我们姑且尝试看看有没有handle什么之类名字的方法吧。

    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;
        }
    }

果不其然,能executeAction,并且通过handler post出去了,猜测应该没问题,那就往上找找看吧。在View的dispatchAttachedToWindow中调用的

        if (mRunQueue != null) {
            mRunQueue.executeActions(info.mHandler);
            mRunQueue = null;
        }
哦,原来当view被attach到window上时,就可以通过handler post出去了。其实呢,跟View post方法的第一个分支一样,只不过保证view一定要执行过attach。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值