Android中消息處理機制主要圍繞消息隊列來實現的。一個線程擁有一個消息隊列之後,就可以進入到一個消息循環中,同時其他線程以及線程本身可以往這個消息隊列發送消息,以便在這個消息被處理時執行一個特定的操作。
Android系統主要是通過MessageQueue、Looper和Handler三個類實現消息處理機制的。其中MessageQueue來描述消息隊列;Looper類用來創建消息隊列以及消息循環;Handler用來發送消息和處理消息。
先看一個典型的Looper線程實例
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
從實例中看出我們先調用了Looper.prepare()在其中會創建消息隊列,Looper.loop()在其中會進行消息循環的過程。Handler進行消息的發送和處理
一、創建線程消息隊列
Android 中消息隊列是使用MessageQueue對象來描述的,它是在Looper的構造方法中創建的,可以通過調用looper的靜態方法prepareMainLooper和prepare方法來實例化Looper。
frameworks/base/core/java/android/os/Looper.java
public final class Looper {
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
public static void prepare() {
prepare(true);
}
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));
}
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
/**
* Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
}
Looper類有一個類型爲ThreadLocal的靜態成員變量sThreadLocal,用來保存線程中的Looper對象。在Looper的靜態成員函數prepare方法中,if語句會檢查當前線程是否已經存在Looper對象,如果存在就會拋出異常;否則就會創建Looper實例並將它保存在Looper的靜態成員變量sThreadLocal中。
prepareMainLooper()方法只能有系統調用,用來創建我們應用程序主線程的消息隊列。Androidxitpng 是在ActivityThread的靜態成員函數main方法中調用的。
一個looper對象在創建過程中,會在構造方法中創建一個MessageQueue對象,並且保存在成員變量mQueue中
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = 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);
}
static const JNINativeMethod gMessageQueueMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit },
{ "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy },
{ "nativePollOnce", "(JI)V", (void*)android_os_MessageQueue_nativePollOnce },
{ "nativeWake", "(J)V", (void*)android_os_MessageQueue_nativeWake },
{ "nativeIsPolling", "(J)Z", (void*)android_os_MessageQueue_nativeIsPolling },
{ "nativeSetFileDescriptorEvents", "(JII)V",
(void*)android_os_MessageQueue_nativeSetFileDescriptorEvents },
};
int register_android_os_MessageQueue(JNIEnv* env) {
int res = RegisterMethodsOrDie(env, "android/os/MessageQueue", gMessageQueueMethods,
NELEM(gMessageQueueMethods));
jclass clazz = FindClassOrDie(env, "android/os/MessageQueue");
gMessageQueueClassInfo.mPtr = GetFieldIDOrDie(env, clazz, "mPtr", "J");
gMessageQueueClassInfo.dispatchEvents = GetMethodIDOrDie(env, clazz,
"dispatchEvents", "(II)I");
return res;
}
在MessagQueue對象的構造方法中調用nativeInit JIN方法在此方法中創建了NativeMessageQueue對象。在register_android_os_MessageQueue方法中mPtr指向了java中MessageQueue的成員變量mPtr
NativeMessageQueue對象在創建的過程中,又會在內部調用C++的Looper對象
NativeMessageQueue::NativeMessageQueue() :
mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = new Looper(false);
Looper::setForThread(mLooper);
}
}
首先調用C++層的Looper類的靜態成員函數getForThread()來獲取當前線程的Looper對象。如果沒有創建過就會創建一個C++層的Looper對象,並保存在NativeMessageQueue類的成員變量mLooper中,然後調用Looper的靜態函數setForThread將當前線程關聯起來。
C++ Looper類的創建過程中,又在內部創建一個管道
Looper::Looper(bool allowNonCallbacks)
: mAllowNonCallbacks(allowNonCallbacks),
mSendingMessage(false),
mPolling(false),
mEpollRebuildRequired(false),
mNextRequestSeq(0),
mResponseIndex(0),
mNextMessageUptime(LLONG_MAX) {
mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0, "Could not make wake event fd: %s", strerror(errno));
AutoMutex _l(mLock);
rebuildEpollLocked();
}
void Looper::rebuildEpollLocked() {
// Close old epoll instance if we have one.
if (mEpollFd >= 0) {
mEpollFd.reset();
}
// Allocate the new epoll instance and register the wake pipe.
mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeEventFd.get();
int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance: %s",
strerror(errno));
for (size_t i = 0; i < mRequests.size(); i++) {
const Request& request = mRequests.valueAt(i);
struct epoll_event eventItem;
request.initEventItem(&eventItem);
int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, request.fd, &eventItem);
if (epollResult < 0) {
ALOGE("Error adding epoll events for fd %d while rebuilding epoll set: %s",
request.fd, strerror(errno));
}
}
}
在Looper中會創建mWakeEventFd,它是unique_fd類型的,在其中會創建一個管道。這個管道在消息循環中起到的作用非常大。首先當一個線程沒有消息需要處理是,它就會睡眠在這個管道的讀端文件描述符上,直到有新的消息需要處理爲止;其次當其他線程向這個線程的消息隊列發送一個消息之後,其他線程就會通過這個寫端文件描述符往這個管道寫入一個數據,從而將這個線程喚醒,以便對剛纔發送到消息隊列中的消息進行處理。