android源码学习-Looper机制

Looper是android当中处理子线程和主线程通信的一个机制,我们顺着源码看一下这种机制是如何工作的。

 

一.Looper如何启动

我们知道,android里面,每一个app都是一个单独的进程,具有独立的内存空间。

java中,一个进程启动的入口就是main方法。所以在android中,一个应用的启动,入口就是ActvitiyThread的main()方法。

 public static void main(String[] args) {
        ...

        Looper.prepareMainLooper();//Looper实例化并且挂载到线程上

        ActivityThread thread = new ActivityThread();
        thread.attach(false);
        ...
        Looper.loop();//Looper机制启动

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

2.Looper的prepareMainLooper()方法

上面我们可以看到,会调用prepareMainLooper的方法,我们看下这个方法。

由于main方法启动后首先会调用该方法,而调用main方法的线程就是主线程。

public static void prepareMainLooper() {
        prepare(false);//主线程为false,子线程为true。该值代表是否允许退出,后面会详细介绍
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

3.Looper的prepare()方法

ThreadLocal是挂载到Thread上的,简单的就可以理解为调用TraceLocal.get方法,不同的线程只会返回当前线程所挂载的唯一对象。通过这个机制保证每个线程有且只有一个Looper对象。

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

4.接下来看下Looper的构造方法。

内部初始化一个MessageQueue,并记录当前线程对象。

至于MessageQueue,我们后续轮训的时候详细分析。

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

二/Looper.loop()轮训

main方法中,调用完了prepare,就调用了loop方法。

这个方法就是一个无限死循环,除非应用程序彻底退出。

public static void loop() {
        final Looper me = myLooper();//拿到当前的loop对象,上面挂载到Thread上,这里就取回
        ...
        final MessageQueue queue = me.mQueue;
        ...
        for (;;) {
            //下面的next方法是关键,有可能会被阻塞,后面单独介绍。
            Message msg = queue.next(); // might block
            
            //我们如果想监控主线程执行的话,就可以获取Looper对象,给mLooggin对象赋值,则每次通过Looper执行任务的前后,都会调用该方法。两次打印时间相减,就是Task在主线程的执行时间。这也是BlockCanary的原理。
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;

            final long traceTag = me.mTraceTag;
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            final long end;
            try {
                //target是handler,每一个Message都绑定一个Handler
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            ...
            msg.recycleUnchecked();
        }
    }

上面有两个疑问:

第一,MessageQueue.next是如何取Message对象的,queue.next()

第二,Handler是如何分发Message的。msg.target.dispatchMessage(msg);

2.Handler.dispatchMessage()

  //这个方法一定是在主线程被调用的。
  public void dispatchMessage(Message msg) {
//如果Message中包含callback(Runnable),则直接执行。我们一般new Hander.post(new Runnable),都是先构造一个包含callback的message,然后添加到MessageQueue队列。
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            //这个Callback就是一个接口,其内部就一个handlerMessage方法。
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            //如果重写了Handler的handlerMessage方法,则会调用到这里。
            handleMessage(msg);
        }
    }

3.MessageQueue的enqueueMessage()方法。

我们一般new Handler().post(new Runnable{});或者postDelayed等,最终都会调用到这个这个方法。

Handler->sendMessageDelayed

Handler->sendMessageAtTime

Handler->enqueueMessage

MessageQueue->enqueueMeesage

boolean enqueueMessage(Message msg, long when) {
        ...
        synchronized (this) {
            ...

            msg.markInUse();
            msg.when = when;//正常的化when为当前时间,delay的话时间为当前时间+delay时间
            Message p = mMessages;
            boolean needWake;
            //mMessages为头节点,如果执行时间小于头节点的,则插入到头节点之前。
            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 {
                //根据when的执行时间,插入到对应的位置,或者队尾。
                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;
    }

4.MessageQueue的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; // 后台空闲线程IdleHandler数量。
        int nextPollTimeoutMillis = 0;//等待时间
        //这里是遍历循环,每次获取一个任务返回Message返回。
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
            //如果nextPollTimeoutMillis>0,则通过natie方法挂起线程,并等待nextPollTimeoutMillis时间在执行。
            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.
//如果链表头的when执行时间大于当前时间,则需要等待nextPollTimeoutMillis时间。
                        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;//标记为-1时,标记为一直阻塞,直到唤醒
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }    
                ...
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                //如果没有空闲handler的话,则继续该循环。阻塞时间为nextPollTimeoutMillis
                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)];
                }
                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);
                }

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

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

失落夏天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值