Android的消息处理有四个核心类:Handler,Looper,Message,MessageQueue,都在android.os包中。
首先分析线程的魔法师Looper:
Looper的字面意思是“循环者”,它被设计用来使一个普通线程编程Looper线程。Looper线程就是循环工作的线程,一旦有新任务就执行,执行完后继续等待下一个任务,这就是Looper线程,使用Looper类创建Looper线程很简单,代码如下:
public class LooperThread extends Thread{
@Override
public void run(){
//将当前线程初始化为Looper线程
Looper.prepare();
public void handleMessage(Message msg){
super.handlerMessage(msg);
switch(msg.what){
case 0:
break;
default:
break;
}
}
//开始循环处理消息队列
Looper.loop();
}
}
通过上面两行核心代码(Looper.prepare()和Looper.loop()),普通线程就升级为Looper线程了,接下来分析这两行代码做了什么
Looper.prepare()将一个普通Thread初始化为LooperThread,这个LooperThread中有一个Looper对象,在Looper对象的内部维护了一个消息队列MessageQueue,注意,一个线程只能有一个Looper对象。why? 下面看源码:
public class Looper{
//每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储对象(TLS)(突然想到orm,好吧,我的思想太发达了,orm就是object reflect model,对象反射模型)
private static final ThreadLocal sThreadLocal=new ThreadLocal();
//Looper内的消息队列
final MessageQueue mQueue;
//当前线程
Thread mThread;
//每个Looper对象中有它的消息队列和它所属的线程
private Looper(){
mQueue=new MesaageQueue();
mRun=true;
mThread=Thread.currentThread();
}
//当我们调用的该方法会在调用线程的TLS中创建Looper对象
public static final void prepare(){
if(sThreadLocal.get()!=null){
//如果在有Looper对象的线程中再次创建Looper对象就会抛出异常
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
}
通过上面的源码就可以清楚的看出Looper.prepare()背后的工作方式了,核心就是把Looper对象定义为ThreadLocal.
接下来就是Looper.loop(),调用这个方法后,它就会不断的从Looper对象内部维护的那个消息队列MQ中取出队头的消息(也叫任务)执行。
源码分析如下:
public static final void loop(){
Looper me=myLooper();//得到当前线程的Looper
MessageQueue queue=me.mQueue;//得到当前looper的消息队列MQ
final long ident=Binder.clearCallingIdentity();
//开始循环
while(true){
Message msg=queue.next();//取出message
if(msg!=null){
if(msg.target==null){
//message没有target,为结束信号,退出循环
return;
}
//很重要,将真正的处理工作交给message的target,也就是Handler.
msg.target.dispatchMessage(msg);
//回收message资源
msg.recycle();
}
}
}
除了prepare()和loop()还有一些其他的有用的方法
Looper.myLooper()得到当前线程的Looper对象。
源码如下:
public static final Looper myLooper(){
//在任意线程调用Looper.myLooper()返回的都是那个线程的Looper对象
return (Loopert)sThreadLocal.get();
}
getThread()得到Looper对象所属线程
public Thread getThread(){
return mThread;
}
quit()结束Looper循环
public void quit(){
//创建一个新的Message,它的target为null,表示结束循环消息
Message msg=Message.obtain();
//发出消息
mQueue.enqueueMessage(msg,0);
}
总结:
1.每个线程有且最多只能有一个Looper对象,他是一个ThreadLocal
2.Looper内部有一个消息队列,loop()方法调用后线程开始不断的从消息队列中取出消息执行。
3.Looper使一个普通线程编程Looper线程。