Android Handler机制——MessageQueue

Android Handler机制——MessageQueue

一、NativeMessageQueue在java层的入口

public final class MessageQueue {
    ......
    @UnsupportedAppUsage
    @SuppressWarnings("unused")
    private long mPtr; // used by native code
    .....
    private native static long nativeInit();
    private native static void nativeDestroy(long ptr);
    @UnsupportedAppUsage
    private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
    private native static void nativeWake(long ptr);
    private native static boolean nativeIsPolling(long ptr);
    private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
}

  mPtr是一个native层的指针,指向NativeMessageQueue的实例。下面六个方法为几个通过jni实现的native调用方法。
  1).nativeInit:顾名思义,这是一个初始化函数,会初始化native层中相关对象,主要作用是实例化一个NativeMessageQueue对象,并将其指针返回到java层被mPtr成员变持有。该方法会在MessageQueue的构造函数中被调用。

    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }

  2).nativeDestroy:取消java层中MessageQueue对native层中NativeMessageQueue对象的引用,主要实现方法是减少对NativeMessageQueue对象的强引用。

static void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->decStrong(env);
}

  该方法会在MessageQueue退出时被调用。


    @Override
    protected void finalize() throws Throwable {
        try {
            dispose();
        } finally {
            super.finalize();
        }
    }

    // Disposes of the underlying message queue.
    // Must only be called on the looper thread or the finalizer.
    private void dispose() {
        if (mPtr != 0) {
            nativeDestroy(mPtr);
            mPtr = 0;
        }
    }


    void quit(boolean safe) {
        ......
        mQuitting = true;
        ....
    }
    
    Message next() {
        ......
        // Process the quit message now that all pending messages have been handled.
        if (mQuitting) {
            dispose();
            return null;
        }
        ......
    }

  3).nativePollOnce:该方法的主要作用是阻塞线程。在native层中,Looper阻塞的主要原理是使用epoll进行阻塞,nativePollOnce最终会调用到epoll_wait方法进行阻塞,只有当epoll中注册的文件描述符触发了唤醒事件时线程才会被唤醒。该方法会在MessageQueue的next方法中被调用,而next又被Looper中的loop方法调用。

    Message next() {
        ......
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);
            ......
        }
        ......
    }

  4).nativeWake:该方法的主要作用是唤醒线程。在native层中最终会调用到write函数向mWakeEventFd所对应的文件写一个字符,用于触发epoll。mWakeEventFd便是native层Looper默认使用的一个唤醒文件描述符,nativePollOnce和nativeWake两个方法最终操作的文件描述符都是它。该方法会被MessageQueue的enqueueMessage方法调用,而enqueueMessage则是在每次Handler发送message时都会被调用。
  needWake是一个标志位,用于标记是否需要唤醒线程,主要由mBlocked成员变量决定。

    boolean enqueueMessage(Message msg, long when) {
        ......
        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
        ......
    }

  5).nativeIsPolling:用于检测epoll是否被阻塞。
  6).nativeSetFileDescriptorEvents:设置epoll绑定的文件描述符。epoll可以绑定多个文件描述符,native层中Looper会默认绑定一个mWakeEventFd,但是它也支持用户绑定其他的文件描述符,该方法便是提供给用户用于绑定其他文件描述符的。一个典型应用便是InputChannel之间的通信(Inputflinger和客户端进行点击事件传输)。

二、构造

Message mMessages;
private final boolean mQuitAllowed;
private long mPtr; // used by native code

MessageQueue(boolean quitAllowed) {
	mQuitAllowed = quitAllowed;
	mPtr = nativeInit();
}

  从MessageQueue的构造可以看出,其主要是两个参数。

  mQuitAllowed的赋值可以追溯到Looper的初始化函数prepare()和prepareMainLooper(),当MessageQueue所负责的线程为主线程时,quitAllowed传入false,子线程传入true,表示MessageQueue是否可以退出。

  mPtr是一个native层的指针,nativeInit()对应的C++层JNI方法如下,所在源码路径为:

  frameworks/base/core/jni/android_os_MessageQueue.cpp

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

  可见,java层nativeInit()方法返回的是一个C++层指针,指向对象类型为NativeMessageQueue。NativeMessageQueue很关键,Handler机制能够实现阻塞、延时等功能依赖于MessageQueue,而MessageQueue实现这些功能则依赖于NativeMessageQueue,当然NativeMessageQueue底层是通过linux的epoll机制实现native层分析后续再写。

  虽然MessageQueue的名字带有Queue,但其本质却是一个链表,当MessageQueue被塞入新的Message时,会对链表进行排序。成员变量mMessages是链表头,Message中也有一个成员变量next用于指向下一个节点的Message。

  类关系图如下所示:
在这里插入图片描述

三、产物(Message)的出、入

  MessageQueue作为生产者消费者模型中的产物仓库(缓冲区),其天然具备两个职责:1.产物放入;2.产物取出。代入Handler场景下,就是Message的存入和取出。MessageQueue只被Handler和Looper依赖,产物的存入、取出功能也分别被它们使用。

1.Message的放入

boolean enqueueMessage(Message msg, long when) {
	if (msg.target == null) {
		throw new IllegalArgumentException("Message must have a target.");
	}
	if (msg.isInUse()) {
		throw new IllegalStateException(msg + " This message is already in use.");
	}

	synchronized (this) {
		if (mQuitting) {	//当MessageQueue已经退出时
			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.markInUse();	//标上正在使用的标志
		msg.when = when;
		Message p = mMessages;
		boolean needWake;
		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 {
			// 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.
			needWake = mBlocked && p.target == null && msg.isAsynchronous();
			Message prev;
			for (;;) {
				prev = p;
				p = p.next;
				if (p == null || when < p.when) {	//插入节点的when时间小于链表中某个节点的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;
}

  当mQuitting==true时,表示MessageQueue的quit方法已被调用,MessageQueue处于退出状态,不会再增加新的Message节点。当插入节点时,会比较Message中的when时间(该时间表示该Message需要被执行的时间),当被插入的Message的when时间小于相比较的节点when时间时,会将被插入的Message放到比较节点的前面,否则放到后面。是的,插入节点时便会根据when时间进行排序,when时间小的在前,大的在后。
  该方法在Handler中调用sendMessage时被调用。

2.Message的取出

  外界可以通过MessageQueue的next()获取Message,Looper的loop()方法中,便是通过queue.next()方法从MessageQueue中获取Message的。

	Message msg = queue.next(); // might block

  看注释可以知道,queue.next()可能会阻塞。是的,当MessageQueue中链表为空或者链表中第一个Message(即when时间最小的Message)的when时间大于当前时间时,next()方法便会阻塞住,知道有新的Message进入或者链表中的第一个Message的when时间大于等于当前时间。

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; // -1 only during first iteration
	int nextPollTimeoutMillis = 0;
	for (;;) {
		if (nextPollTimeoutMillis != 0) {
			Binder.flushPendingCommands();
		}

		nativePollOnce(ptr, nextPollTimeoutMillis);	//调用native方法阻塞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) {	//当Message没有绑定Handler时,放弃这个Message,一般不会出现这种情况
				// 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) {	//当前时间小于Message的when时间(message的指定执行时间)
					// Next message is not ready.  Set a timeout to wake up when it is ready.
					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;	//将message从链表中取出
					}
					msg.next = null;
					if (DEBUG) Log.v(TAG, "Returning message: " + msg);
					msg.markInUse();
					return msg;	//返回message
				}
			} else {
				// No more messages.
				nextPollTimeoutMillis = -1;	//为-1时nativePollOnce会无限阻塞下去
			}

			// Process the quit message now that all pending messages have been handled.
			if (mQuitting) {	//如果MessageQueue已经退出了,先调用dispose()销毁native资源,然后返回null
				dispose();
				return null;
			}

			// If first time idle, then get the number of idlers to run.
			// Idle handles only run if the queue is empty or if the first message
			// in the queue (possibly a barrier) is due to be handled in the future.
			if (pendingIdleHandlerCount < 0
					&& (mMessages == null || now < mMessages.when)) {
				pendingIdleHandlerCount = mIdleHandlers.size();
			}
			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);
			}s

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

  next()方法的主体是一个循环。进入循环首先会调用nativePollOnce这个native方法来阻塞nextPollTimeoutMillis这么长时间,而第一次进入循环时nextPollTimeoutMillis=0,不会阻塞。以上代码分析都有注释,可看注释。

三、停止

  Handler机制的停止关键便是MessageQueue的停止,当用户调用Looper的quit时,Looper便会执行MessageQueue的quit方法。quit有一个传参safe,其决定是否执行完所有的非延时message。

void quit(boolean safe) {
	if (!mQuitAllowed) {
		throw new IllegalStateException("Main thread not allowed to quit.");
	}

	synchronized (this) {
		if (mQuitting) {
			return;
		}
		mQuitting = true;

		if (safe) {
			removeAllFutureMessagesLocked();
		} else {
			removeAllMessagesLocked();
		}

		// We can assume mPtr != 0 because mQuitting was previously false.
		nativeWake(mPtr);
	}
}

private void removeAllFutureMessagesLocked() {
	final long now = SystemClock.uptimeMillis();
	Message p = mMessages;
	if (p != null) {
		if (p.when > now) {	//链表里所有的Message的when时间都大于当前时间,则将链表中所有message都销毁
			removeAllMessagesLocked();
		} else {
			Message n;
			for (;;) {	//取出链表里Message的when时间小于等于当前时间的message执行,然后将其他的message销毁
				n = p.next;
				if (n == null) {
					return;
				}
				if (n.when > now) {
					break;
				}
				p = n;
			}
			p.next = null;
			do {
				p = n;
				n = p.next;
				p.recycleUnchecked();
			} while (n != null);
		}
	}
}

private void removeAllMessagesLocked() {
	Message p = mMessages;
	while (p != null) {
		Message n = p.next;
		p.recycleUnchecked();	//将Message中的成员变量全部置0或置空
		p = n;
	}
	mMessages = null;
}

protected void finalize() throws Throwable {
	try {
		dispose();
	} finally {
		super.finalize();
	}
}

private void dispose() {
	if (mPtr != 0) {
		nativeDestroy(mPtr);
		mPtr = 0;
	}
}

  需要注意的是,当销毁MessageQueue后,一定要调用dispose方法销毁native层资源。

四、Handler机制UML图

在这里插入图片描述

五、流程图

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值