handler——Looper线程详解

转自http://www.jb51.net/article/33514.htm

Looper的字面意思是“循环者”,它被设计用来使一个普通线程变成Looper线程。所谓Looper线程就是循环工作的线程。在程序开发中(尤其是GUI开发中),我们经常会需要一个线程不断循环,一旦有新任务则执行,执行完继续等待下一个任务,这就是Looper线程。使用Looper类创建Looper线程很简单:

publicclass LooperThread extends Thread {
@Override
publicvoid run() {
// 将当前线程初始化为Looper线程
Looper.prepare();

// ...其他处理,如实例化handler

// 开始循环处理消息队列
Looper.loop();
}
}

通过上面两行核心代码,你的线程就升级为Looper线程了!!!是不是很神奇?让我们放慢镜头,看看这两行代码各自做了什么。



通过上图可以看到,现在你的线程中有一个Looper对象,它的内部维护了一个消息队列MQ。注意,一个Thread只能有一个Looper对象,为什么呢?咱们来看源码。

publicclass Looper {
// 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象
privatestaticfinal ThreadLocal sThreadLocal =new ThreadLocal();
// Looper内的消息队列
final MessageQueue mQueue;
// 当前线程
Thread mThread;
// 。。。其他属性

// 每个Looper对象中有它的消息队列,和它所属的线程
private Looper() {
mQueue =new MessageQueue();
mRun =true;
mThread = Thread.currentThread();
}

// 我们调用该方法会在调用线程的TLS中创建Looper对象
publicstaticfinalvoid prepare() {
if (sThreadLocal.get() !=null) {
// 试图在有Looper的线程中再次创建Looper将抛出异常
thrownew RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
// 其他方法
} 

通过源码,prepare()背后的工作方式一目了然,其核心就是将looper对象定义为ThreadLocal。如果你还不清楚什么是ThreadLocal,请参考《理解ThreadLocal》。

2)Looper.loop()


调用loop方法后,Looper线程就开始真正工作了,它不断从自己的MQ中取出队头的消息(也叫任务)执行。其源码分析如下:

publicstaticfinalvoid loop() {
Looper me = myLooper(); //得到当前线程Looper
MessageQueue queue = me.mQueue; //得到当前looper的MQ

// 这两行没看懂= = 不过不影响理解
Binder.clearCallingIdentity();
finallong ident = Binder.clearCallingIdentity();
// 开始循环
while (true) {
Message msg = queue.next(); // 取出message
if (msg !=null) {
if (msg.target ==null) {
// message没有target为结束信号,退出循环
return;
}
// 日志。。。
if (me.mLogging!=null) me.mLogging.println(
">>>>> Dispatching to "+ msg.target +""
+ msg.callback +": "+ msg.what
);
// 非常重要!将真正的处理工作交给message的target,即后面要讲的handler
msg.target.dispatchMessage(msg);
// 还是日志。。。
if (me.mLogging!=null) me.mLogging.println(
"<<<<< Finished to "+ msg.target +""
+ msg.callback);

// 下面没看懂,同样不影响理解
finallong newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf("Looper", "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);
}
// 回收message资源
msg.recycle();
}
}
} 


除了prepare()和loop()方法,Looper类还提供了一些有用的方法,比如

Looper.myLooper()得到当前线程looper对象

publicstaticfinal Looper myLooper() { // 在任意线程调用Looper.myLooper()返回的都是那个线程的looper
return (Looper)sThreadLocal.get(); }
getThread()得到looper对象所属线程:

public Thread getThread() {
 return mThread;
 }

quit()方法结束looper循环:

publicvoid quit() {
// 创建一个空的message,它的target为NULL,表示结束循环消息
Message msg = Message.obtain();
// 发出消息
mQueue.enqueueMessage(msg, 0);
} 


到此为止,你应该对Looper有了基本的了解,总结几点:


1.每个线程有且最多只能有一个Looper对象,它是一个ThreadLocal


2.Looper内部有一个消息队列,loop()方法调用后线程开始不断从队列中取出消息执行


3.Looper使一个线程变成Looper线程。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值