Looper作为Android中线程间通讯的核心,起着至关重要的作用。它与Handler,MessageQueue一起封装了一套完整的通讯机制。
在调用Looper时,需要先执行prepare() 接着就可以loop()开始接收消息了。我们从来没有在应用的主线程中调用prepare()是因为在ActivityThread的main方法中
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
系统已经帮我们初始化过了。
实际上这个静态的prepare方法做的是:初始化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));
}
Looper的构造方法里,实例化了成员mQueue(一个MessageQueue)
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
最终调用jni函数nativeInit中,当然这个函数也是在AndroidRuntime.cpp中动态注册的。
它的实现在frameworks\base\core\jni\android_os_MessageQueue.cpp中,返回NativeMessageQueue的指针
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);
}
这个NativeMessageQueue又是做什么的呢?找到它的原型与构造
class NativeMessageQueue : public MessageQueue, public LooperCallback {
public:
NativeMessageQueue();
virtual ~NativeMessageQueue();
virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj);
void pollOnce(JNIEnv* env, jobject obj, int timeoutMillis);
void wake();
void setFileDescriptorEvents(int fd, int events);
virtual int handleEvent(int fd, int events, void* data);
private:
JNIEnv* mPollEnv;
jobject mPollObj;
jthrowable mExceptionObj;
};
NativeMessageQueue::NativeMessageQueue() : //构造
mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = new Looper(false); //Looper.cpp
Looper::setForThread(mLooper);
}
}
就是一个MessageQueue,而他的实现还要关联到Looper.cpp,瞅一眼pollOnce()、wake()、setFDEvents()的实现,可以发现这也是个代理,真正的函数实现都是Looper来完成的。setForThread与getForThread中用pthread实现TLS多线程访问解构函数安全。
至此prepare调用完毕,下面通常接着调用loop()开始循环。这也是Looper.java类的两大使命之二。
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; //获取验证当前线程是否prepare完毕
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity(); //标记线程id
for (;;) {
Message msg = queue.next(); // might block 阻塞获取msg如果返回null则messageQueue已经退出
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg); //这里的target就是handler 迪米特法则
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity(); //比对线程id 不同报错。这个操作目的是发现任务分发过程中:线程崩溃
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
可以看到阻塞获取msg的具体实现要到MessageQueue.next()中去继续寻找了