欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android基础之Handler机制(三)之MessageQueue源码分析

程序员文章站 2022-07-14 16:45:16
...

基于8.0.0源码

##定义##

	/**
	* Low-level class holding the list of messages to be dispatched by a
	* {@link Looper}.  Messages are not added directly to a MessageQueue,
	* but rather through {@link Handler} objects associated with the Looper.
	*
	* <p>You can retrieve the MessageQueue for the current thread with
	* {@link Looper#myQueue() Looper.myQueue()}.
	*/

个人理解

  • MessageQueue是一个内部维护一个消息列表,并通过Looper来派发Message的类. Messages并不是直接添加到MessageQueue里,而是通过和Looper有关系的Hander来添加的.

  • 我们可以在当前线程通过Looper.myQueue()来获取当前线程的MessageQueue.

方法细节

MessageQueue类

  • final class MessageQueue
    • 可以看到MessageQueue是被final修饰的类,那么我们知道final修饰类的特点: final类不能被继承,也没有子类,内部方法默认也是final修饰.
    • Google处于安全考虑,把MessageQueue定义成了final类.

构造方法

 MessageQueue(boolean quitAllowed) {
	//赋值给类变量mQuitAllowed,类变量指如果MessageQueue可以退出的话那么这个变量就为true
    mQuitAllowed = quitAllowed;
	//掉用nativeInit()方法,返回的是一个long类型,暂时不谈论Native层方法
    mPtr = nativeInit(); //初始化方法
}
  • 系统提供了一个有参的构造来创建MessageQueue, quitAllowed意思是指是否可以手动退出.MessageQueue是依附于Looper的.Android中规定UI线程中是不可以手动退出MessageQueue的,因为UI线程(主线程)避免误操作.而其他工作线程是可以手动退出MessageQueue.

消息入队enqueueMessage方法

源码分析:

boolean enqueueMessage(Message msg, long when) {
	//如果msg的target对象也就是宿主Handler的对象为空,就抛出异常
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
	//如果msg的状态是in-use状态,就抛出异常
    if (msg.isInUse()) {
        throw new IllegalStateException(msg + " This message is already in use.");
    }
	
    synchronized (this) {
		//如果当前MessageQueue已经退出,就抛出异常
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }
		//把Msg的状态置为in-user,when属性赋值,
        msg.markInUse();
        msg.when = when;
		//拿到msg队列头
        Message p = mMessages;
		//是否需要唤醒线程
        boolean needWake;
		//当队列等于空,when的时间等于0,传入的when比队列头的when时间小的时候
        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
			//插入到头部,赋值,如果线程block则唤醒
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            // Inserted within the middle of the queue.  Usually we don't have to wake
            // up the event queue unless there is a barrier at the head of the queue
            // and the message is the earliest asynchronous message in the queue.
			//线程堵塞或者msg的宿主Handler对象为空,msg是异步操作的时候
            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;
}

消息入队总结:

    1. 先校验msg的宿主Handler是否存活,msg的状态是被使用,MessageQueue是否已经退出.
    1. 满足队列为空,处理时间等于0,传入的when比队列头的when要小的时候, 插入到队列的头优先处理.
    1. 以上情况都不满足的时候,从头遍历队列根据被处理时间找到它的位置.

消息出队 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.
	//mPtr是Native层返回的NativeMessageQueue的地址,在构造方法中初始化得到值. 如果等于0就说明队列不存在或者被清空了.
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }
	
	//第一次初始化的时候为 -1,待处理的IdleHandler数量
    int pendingIdleHandlerCount = -1; // -1 only during first iteration
	//线程阻塞的时间, -1 表示一致阻塞, 0 表示不阻塞, > 0 表示阻塞 nextPollTimeoutMillis长时间
    int nextPollTimeoutMillis = 0;
    for (;;) {
		//死循环,代码省略
		//对消息出队做处理
		...
        }

        // Reset the idle handler count to 0 so we do not run them again.
		//把idleHandler的数量置为 0
        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;
    }
}
相关标签: MessageQueue