这一章主要讲Handler、Looper、MessageQueue这几者之间工作的机制,其实对于上层开发者,Handler用起来容易,但其背后的机制、尤其是Looper的机制却比较复杂,对某些部分,我暂时只能从一定程度上理解。
ThreadLocal
对于每一个线程,需要独立拥有一个Looper来进行消息管理。这个时候就需要派上ThreadLocal了。
ThreadLocal适合去维护一些以线程为作用域、不同线程使用的是不同的拷贝这种情景。
参考如下链接:http://blog.csdn.net/lufeng20/article/details/24314381 讲得比较清楚。
其实现是依赖Thread类中有如下定义:ThreadLocal.ThreadLocalMap threadLocals = null;
也就是每一个Thread对象都有一个threadLocals变量,类型是ThreadLocalMap,而这个类中有如下定义:private Entry[] table;
,这个Entry就是用来存放每一个ThreadLocal对象的容器。
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
所以容易理解了,ThreadLocal存储过程就是以ThreadLocal自身的对象为key,泛型Object作为value,保存到ThreadLocalMap里的table数组中。而每个Thread都会拥有各自的ThreadLocalMap。
Looper+MessageQueue原理
调用Looper.prepare,来在一个新的线程中做初始化准备,这里面包括了构造一个新的Looper,保存当前的线程,构造新的MessageQueue。
调用Looper.loop,开始进入循环来等待接收消息。其主要是通过调用messageQueue的next()来等待新消息,再取出message,调用message.target.dispatchMessage(message)来处理此消息。message的target是Handler。这样即可完成消息的传递了。
似乎一切顺理成章,但有没有想过为何子线程中调用了loop后,进入了死循环但仍然不影响线程后面代码的执行?贴上两个链接:
下面贴上我的一些测试,用以帮助理解,先说结论:Looper.loop方法是会阻塞运行的,即loop方法后面的代码在looper调用quit之前是不会执行的。见下面测试:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Thread1 t1=new Thread1();
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message message = new Message();
message.setTarget(t1.handler);
message.what=10;
t1.handler.sendMessage(message);
}
},"thread2");
t2.start();
}
class Thread1 extends Thread{
int i=0;
Handler handler;
@Override
public void run() {
Looper.prepare();
handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(Message msg) {
System.out.println("ssssssssss==================="+i);
Looper.myLooper().quit();
}
};
i=5;
Looper.loop();
i=100;
// System.out.println("ssssssssss==================="+i);
}
}
}
执行结果如下:
04-16 20:33:44.368 4852-4885/com.zerastudio.test0416 I/System.out: ssssssssss===================5
去掉最后一行的注释后,执行结果:
04-16 20:34:58.651 6289-6321/com.zerastudio.test0416 I/System.out: ssssssssss===================5
04-16 20:34:58.651 6289-6321/com.zerastudio.test0416 I/System.out: ssssssssss===================100
足以说明了Looper调用了loop后会阻塞执行的,只有在调用了quit后才会继续往后执行。稍后会对ActivityThread进行研究,而Activity的各个生命周期均是从Looper的loop方法中开始被调用的。
Handler原理
在子线程中,通过目标线程的handler.obtainMessage,得到一个以目标线程handler作为target的message后,设置message信息,再用handler.send发送,也就是调用handler持有的messageQueue(来自Looper)的enqueueMessage插入到队列里,结合上面说的机制,唤醒loop,又转到了目标线程Handler的dispatchMessage方法里,于是切换了线程,就可以完成指定的动作了。
Message.obtain和new Message区别
Message维护了一个全局的messagePool,默认大小好像是50,回收利用对内存的消耗更小也更快。