美文网首页
handler-主线程消息循环的创建流程

handler-主线程消息循环的创建流程

作者: lvcs | 来源:发表于2019-08-23 15:32 被阅读0次

    1.在ActivityThread的main方法中开启主线程的消息循环

    在其它线程中创建Looper可使用 Looper.prepare()方法

    //ActivityThread#main
    public static void main(String[] args) {
    ......
        //将当前线程初始化为looper,将其标记为应用程序的主循环。
        Looper.prepareMainLooper();
    .......
        //让Looper工作处理消息,开始消息循环
        Looper.loop();
    .......
    }
    

    2.创建UI线程Looper

    在创建Looper的同时,创建MessageQueue,绑定当前线程,并将Looper放入ThreadLocal进行线程分离,每个线程将调用自己的Looper进行使用。

    //Looper
    public final class Looper {
     //装载不同线程Looper的容器
     static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
     //应用程序的主循环器,它位于应用程序的主线程中
     private static Looper sMainLooper;  
     //与此Looper关联的消息队列
     final MessageQueue mQueue;
     //与此Looper关联的线程
    final Thread mThread;
     
    //Looper构造方法  创建消息队列,获取当前线程
    private Looper(boolean quitAllowed) {
        //创建消息队列   
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
       }
    }
    
    //创建主程序Looper
    public static void prepareMainLooper() {
         //创建Looper 主线程传入false参数,禁止退出消息循环(其它线程都为true,可退出)
         prepare(false);
         synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            //返回与当前线程关联的Looper对象。如果调用线程未与Looper关联,则返回null。
            sMainLooper = myLooper();
         }
    }   
     
     //创建新Looper,并将其放入ThreadLocal中
    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));
    }
    

    3.创建MessageQueue

    分别创建Java层MessageQueue和native层的MessageQueue

    //MessageQueue
    public final class MessageQueue {
     //是否可以退出消息队列
     private final boolean mQuitAllowed;
     //当前looper待处理的消息
     Message mMessages;
     private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
     private IdleHandler[] mPendingIdleHandlers;
    
    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
         //创建native层的MessageQueue 
        mPtr = nativeInit();
        }      
    }
    
    //android_os_MessageQueue.cpp#android_os_MessageQueue_nativeInit
    static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
        NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
        if (!nativeMessageQueue) {
            jniThrowRuntimeException(env, "Unable to allocate native queue");
            return 0;
        }
        nativeMessageQueue->incStrong(env);
        return reinterpret_cast<jlong>(nativeMessageQueue);
    }
    
    //android_os_MessageQueue.cpp#NativeMessageQueue
    //Native Looper调用静态方法getForThread(),获取当前线程中的Looper对象。如果为空,则创建Native Looper对象
    NativeMessageQueue::NativeMessageQueue() :
            mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {       
        mLooper = Looper::getForThread();
        if (mLooper == NULL) {
            mLooper = new Looper(false);
            Looper::setForThread(mLooper);
        }
    }
    
    

    4.Looper.loop()开启循环

    //Looper 
    public static void loop() {
        //在ThreadLocal中获取当前线程的Looper 
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        //获取与此Looper绑定的MessageQueue 
        final MessageQueue queue = me.mQueue;
    ......
        //死循环
        for (;;) {
            // //获取MessageQuene消息队列的消息.
            Message msg = queue.next(); 
            if (msg == null) {
                //如果没有消息则return,阻塞在这里等待获取Message。
                return;
            }
    ......
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                //msg.target 是Message里的Handler    写入跟踪消息已经开始
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
    ......
            try {
                //让与Message关联的Handler通过dispatchMessage()处理Message。
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    //结束
                    Trace.traceEnd(traceTag);
                }
            }
     ......
            //重新循环可能正在使用的消息
            msg.recycleUnchecked();
        }
    }
    

    5.MessageQueue .next()取出消息

    消息的处理会优先处理Native层的消息,其次才处理Java层的消息。
    在正常时候,我们发送的Message全都是同步消息,当然我们也可以发送异步消息。
    当开启了同步障碍,Looper在获取下一个要执行的消息时,会在链表中寻找第一个要执行的异步消息,如果没有找到异步消息,就让当前线程沉睡。实质上是一个对消息队列的优先级实现。

    //MessageQueue 
    Message next() {
        
        final long ptr = mPtr;
        //如果native层的looper被放弃的时候(调用了quit方法)返回null
        if (ptr == 0) {
            return null;
        }
        //-1仅在第一次迭代期间
        int pendingIdleHandlerCount = -1;
        int nextPollTimeoutMillis = 0;
        //死循环
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
            //阻塞方法,主要是通过native层的epoll监听文件描述符的写入事件来实现的。
            //如果nextPollTimeoutMillis=-1,一直阻塞不会超时
            //如果nextPollTimeoutMillis=0,不会阻塞,立即返回。
            //如果nextPollTimeoutMillis>0,最长阻塞nextPollTimeoutMillis毫秒(超时),如果期间有程序唤醒会立即返回。
            nativePollOnce(ptr, nextPollTimeoutMillis);
    
            synchronized (this) {
                //获取系统开机到现在的时间
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                //msg是最后查找到的消息,这里初始化为消息队列的队头消息
                Message msg = mMessages;
                //如果当前开启了同步障碍
                if (msg != null && msg.target == null) {
                     //msg.target == null表示此消息为消息屏障(通过postSyncBarrier方法发送来的)
                     //处理同步障碍,会循环找出第一个异步消息(同步障碍消息)
                     //所有同步消息都将忽略(平常发送的一般都是同步消息)
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                     // 如果这个消息是同步的,那么继续向下找异步的
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // 如果当前消息的执行时间没到,让它沉睡到下个消息的执行时间,设置一下阻塞时间nextPollTimeoutMillis
                        //进入下次循环的时候会调用nativePollOnce(ptr, nextPollTimeoutMillis)进行阻塞;
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        //正常取出消息,不需要等待时间或者等待时间已经到了,那么直接返回该消息
                        //从消息队列中删除待返回的msg(剪断链表)
                        //设置mBlocked = false代表目前没有阻塞
                        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 {
                    //没有消息,会一直阻塞,直到被唤醒
                    nextPollTimeoutMillis = -1;
                }
    
                // 判断是否已经退出了
                if (mQuitting) {
                    dispose();
                    return null;
                }
    
                //获取空闲时处理任务的handler 用于发现线程何时阻塞等待更多消息的回调接口。
                if (pendingIdleHandlerCount < 0
                            && (mMessages == null || now < mMessages.when)) {
                        pendingIdleHandlerCount = mIdleHandlers.size();
                 }
                    //如果空闲时处理任务的handler个数为0,继续让线程阻塞
                 if (pendingIdleHandlerCount <= 0) {
                        // No idle handlers to run.  Loop and wait some more.
                        mBlocked = true;
                        continue;
                  }
                    //判断当前空闲时处理任务的handler是否是为空
                 if (mPendingIdleHandlers == null) {
                        mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                    }
                    mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
                }
    
                //只有第一次迭代的时候,才会执行下面代码
                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);
                        }
                    }
                }
    
            //重置空闲的handler个数,因为不需要重复执行
            pendingIdleHandlerCount = 0;      
           //当执行完空闲的handler的时候,新的native消息可能会进入,所以唤醒Native消息机制层
            nextPollTimeoutMillis = 0;
        }
    }
    

    相关文章

      网友评论

          本文标题:handler-主线程消息循环的创建流程

          本文链接:https://www.haomeiwen.com/subject/abftectx.html