在学习android过程中,我们是知道的,一个线程对应一个Loop,同时Activity默认的UI线程会有对应的默认生成的Loop,那么为什么这样呢?没事看看源码可以得到更多的信息。
我们从使用主线程的Looper分析:
在Activity被被创建之前,会首先创建UI线程,也就是ActivityThread实例,其中含有入口。
publicstaticvoid main(String[] args)中含有
Looper.prepareMainLooper();来创建该UI线程中的Looper
Looper.loop();来循环控制分发所得到的Message
由此,Activity便默认产生了一个UI线程的Loop
那么这时候呢,这个主Loop便在UI线程不断的循环,一直跑。
下面来看看Loop的源码,其实主要要注意两个方法prepare()和loop()
其中主要是:
publicstaticvoid prepare() {
if (sThreadLocal.get() != null) {
thrownew RuntimeException("Only one Looper may be created per thread");}
sThreadLocal.set(new Looper());}//Prepare()用于初始化Looper实例
private Looper() {
mQueue = new MessageQueue();//同时初始化了MessageQueue()
mRun = true;
mThread = Thread.currentThread();
}
首先之前的判断语句保证了,一个线程里只能含有一个Looper实例,否则要出问题。
下面来看看sThreadLocal变量,可以来看看这个是表示的什么:
Staticfinal ThreadLocal<Looper>sThreadLocal =new ThreadLocal<Looper>();
看ThreadLocal类的源码,可以了解到,其实就是一个通用容器,含有get(),set()等等方法,这里用于存放Looper实例。
接下来我们看看sThreadLocal.set(new Looper());这个语句都做了些啥?
publicvoid set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
原来set中所做的工作无非就是初始化Values(如果当前线程并没有初始化Values的时候),并将对应的Looper实例放入Values中一个Object数组中(table),这个存放的Values是以Thread作为划分的。
OK,接下面来分析Loop方法:
publicstaticvoid loop() {
//获取当前线程存在的Looper对象
Looper me = myLooper();
if (me == null) {
thrownew RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//获取该Looper对象中的MessageQueue实例
MessageQueue queue = me.mQueue;
// 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();
finallong ident = Binder.clearCallingIdentity();
//一个无线循环遍历该MessageQueue对象,获取对应的含有的Message对象
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
//这里提前说明下msg.target其实就是对应的Handler对象
// No target is a magic identifier for the quit message.
return;
}
long wallStart = 0;
long threadStart = 0;
// 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);
wallStart = SystemClock.currentTimeMicro();
threadStart = SystemClock.currentThreadTimeMicro();
}
//调用Handler的消息分发方法,下面详细介绍
msg.target.dispatchMessage(msg);
if (logging != null) {
long wallTime = SystemClock.currentTimeMicro() - wallStart;
long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
if (logging instanceof Profiler) {
((Profiler) logging).profile(msg, wallStart, wallTime,
threadStart, threadTime);
}
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
finallong newIdent = Binder.clearCallingIdentity();
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.recycle();//消息分发以后,释放该Message实例
}
}
}
总而观之,loop要做的事情就是不断的在该线程中循环遍历该Looper实例所对应的MessageQueue.如果MessageQueue被塞入了Message,则将其dispatchMessage掉。
这里可以知道msg.target.dispatchMessage(msg);中的msg.target就是Message对应的Handler实例,来源可以来看Handler的源码。
我们在平时使用Handler的时候无非就是初始化,然后使用sendMessage,然后handleMessage
一起来分析下,首先是初始化工作:
public Handler() {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
thrownew RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = null;
}
看看myLooper是个啥东东。
publicstatic Looper myLooper() {
returnsThreadLocal.get();
}
原来就是获取之前说的sThreadLocal中set进去的Looper实例,一个线程对应一个LOOPER实例,没得选咯,只能获取到初始化Handler方法的那个线程对应的Looper实例了。
接下来就是获取到Looper对应的MessageQueue对象。
下面sendMessageà sendMessageDelayedà sendEmptyMessageAtTime,就是这个咯。
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
msg.target = this;这里就把自己实例赋值给了msg.target,
同时enqueueMessage 把Message实例塞进了MessageQueue,链表实现的哦,这里不做详细介绍。
之前在Looper.looper中看到了
msg.target.dispatchMessage(msg);
看看这段源码:
publicvoid dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
这里暂时不讨论Message以及Handler所给出的CallBack接口,
handleMessage(msg);便是我们自己所重写的那个方法。
这样一来,整个消息循环机制流程就清楚。
归纳下,如果我们从简单入手,就知道在UI线程中,已经为我们初始化了一个主Looper实例,归属于主线程(UI线程),接下来,Looper.loop()在该线程中就一直不断的循环,dispathMessage,分发消息。
Handler的sendMessage其实就是把Message塞到了对应线程对应的Looper实例的那个MessageQueue中,然后捏,dispathMessage其实就是分发该消息,同时可以由自己的重写的hanleMessage方法来获取,做对应的工作。
当然,在非UI线程消息机制也是一样的道理,此处不详述咯
随笔随笔,估计会有很多不足以及错误的地方,希望大家能帮忙指正,谢谢各位看官。
原创作品,转载请注明http://blog.csdn.net/vc_player/article/details/7876762