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

2019-08-23  本文已影响0人  lvcs

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;
    }
}
上一篇下一篇

猜你喜欢

热点阅读