先说说Looper类:Looper就是为每一个线程创建一个Looper对象,维护一个MessageQueue,并循环从MessageQueue中取出消息并分发给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干了些什么事
public static void prepare() {
prepare(true);
}
//判断当前线程是否有Looper对象,没有则new一个并放到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));
}
至于这个地方为什么要用ThreadLocal来存储Looper对象呢:
我们知道ThreadLocal是与线程相关的一个类,系统规定每个线程只能有一个Looper对象,也就是说只能由一个MessageQueue对象,这样便于维护消息队列。如果我已经prepare一次了,那么我的当前线程中是有Looper对象的,并存储在当前线程变量内。当你再在此线程prepare时,ThreadLocal对象会获取当前线程是否有Looper对象,如果有,直接抛异常,这是系统所不允许的,
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
因此ThreadLocal用来存储Looper对象,设计的真鸡贼,不知道大家还有没有别的方式来控制一个线程只有一个Looper对象。看到很多博客都说ThreadLocal是用来并发控制资源共享的,ThreadLocal存储每个线程对资源的副本,再次本人觉得纯属扯淡,你去看看ThreadLocal的例子,如果ThreadLocal存储副本,你丫的把“主本”给我找出来?通过Looper就可以看出来ThreadLocal只是存储当前线程的相关变量。
创建完Looper对象,并初始化了MessageQueue对象,下面该进入不断循环,取出消息了:
public static void loop() {
final Looper me = myLooper();//你看,每次都是myLooper获取当前线程的Looper对象,免得获取到别的线程的了
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final 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();
final long ident = Binder.clearCallingIdentity();
for (;;) {//死循环吧
Message msg = queue.next(); // 从队列中获取下一个
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);
}
//获取到消息之后分发给HAndler处理,其实这个Handler就是target
msg.target.dispatchMessage(msg);
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();
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对象,重复利用就在此,哈哈。。下面会讲
}
}
至此,Looper的主要工作讲完了。
接着是Message,就是携带了一些数据,被handler带着飞。重复利用问题以及链表的结构。
先看看都带了什么数据:
/*package*/ int flags;
/*package*/ long when;//时间而已
/*package*/ Bundle data;//数据
/*package*/ Handler target; //Handler,表明我这个Message要被哪个Handler处理,当然是谁发送我,谁处理,发送我的时候给我赋值
/*package*/ Runnable callback; //post(Runnable r)函数使用
// sometimes we store linked lists of these things
/*package*/ Message next;//链接下一个Message
再看看重复利用:
public void recycle() {
clearForRecycle();//把要回收的这个Message数据清空
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {//不超过50个,源码的常量
next = sPool;
sPool = this;//关键在这,又把这个对象赋给了静态的sPool引用,gc不会回收此Message
sPoolSize++;
}
}
}
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}
看吧,我们obtain的时候会利用刚才回收掉的Message,否则才new Message();
再看MessageQueue,他里面并不真正的使用数组的形式去存储一系列的Message,而是通过Message的next使用链表的形式维护Message队列,只要能拿到链表的第一个Message就可以展开一系列的循环读取Message。通过next()方法获取。代码就不贴了。
最后是Handler类介绍:创建一个Handler对象,一般都会重写handleMesage方法。去处理我们发送过来的消息,handleMessage何时被调用呢,看下
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);//处理handler.post(Runnable r)的
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);//调用了吧
}
}
那么dispatchMessage的调用呢,看前面的Looper.loop(),娶到一个Message之后,通过Message 的target(Handler)调用到的,这样处理的过程。
再看看Handler的发送:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;//这个很重要就是把此Handler对象直接赋给此Message的target,
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);//这个就是把此Message对象加入MessageQueue
}
这样,整个流程就走完了,发送到加入队列,再取,在处理的流程。
发送是Handler,加入队列是MessageQueue,取是Looper(内部也是MesageQueue取的,不过是有Looper维护此队列而已),处理是Handler。
Activity主线程,在程序中的main方法已经prepare了,并且loop了,所以我们没必要创建Looper对象。
在我们自己创建的子线程中,我们要想处理消息,必须Looper.prepare,并且loop()。
来源:oschina
链接:https://my.oschina.net/u/1254864/blog/213705