在使用handler时,会有在子线程创建handler的场景,那我们从Looper.java的源码中摘抄下面一段创建Hander的代码段:
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();
}
}
上面是一般使用在子线程创建和使用Handler的代码段,我们对比以前在主线程创建和使用Handler的代码,可以发现基本差不多,但是有一点不一样,那就是在子线程中多了下面这两行代码:
Looper.prepare();
Looper.loop();
就是子线程需要prepare,可以直接理解为组要准备当前线程的looper。就是说子线程没有looper,那我们看看我们怎么准备looper的?
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
prepare(true);
}
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));
}
源码的注释也说得很清楚,就是创建handler需要先有looper。prepare()方法里面是调用了prepare(boolean quitAllowed)方法,后面这个方法比前面就多了个参数,这个参数【quitAllowed】看字面意思可以看出作用就是:允不允许looper退出,从代码中我们可以知道子线程的looper是可以退出的;然后在prepare(boolean quitAllowed)中首先检查时候已经存在looper了,如果已经含有了looper,那就报错,这下我们就知道了Android是怎么保证一个线程只有一个looper了,如果当前线程还不存在looper,那就直接new一个新的looper,然后将创建的looper塞进sThreadLocal中。
那么子线程中loop()方法是什么呢?这个loop()方法就是在当前线程中运行消息队列,并切在结束时需要调用quit()方法.我们接着针对loop()看看源码里面做了什么:
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
...
try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
}
....
msg.recycleUnchecked();
}
}
在loop()方法中主要就是从消息队列中获取消息,然后执行信息分发【这个具体先不深入,我们只要知道loop()的主要工作就行】,对比一下我们在主线程中使用Handler的情况,在子线程中使用Handler很像是条件不好人要自立更生艰苦奋斗,没有条件就自己创造条件。
我们看了子线程中如何使用Handle和相关源码分析,接下来再看看主线程中我们是怎么使用handler的?根据以前的经验,主线程创建使用Handler就是直接创建的,并没有其他的操作:
public Handler mHandler;
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
相比子线程,使用时少了prepare()和loop();但是真的是主线程不需要调用这些方法吗?显然不是的,子线程有的主线程也不能少,那接下来我们看看是谁帮了我们的忙?
还记得之前在Android_Application启动梳理时,就发现了在ActivityThread的面main函数就有这么两行行代码:
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop();
}
那我们就看看这个prepareMainLooper()方法是做了什么:
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
这个prepareMainLooper()里面就是调用了prepare()方法,但是传入的参数和在子线程中不同,这里这传入的是false,也就是说主线程的looper是不允许退出的;到这里,我们知道prepareMainLooper将当前线程初始化为循环程序,将其标记为应用程序的主循环程序。应用程序的主循环是由android环境创建的,因此用户不必自己调用此函数
在prepareMainLooper()方法后也调用了loop()方法,看到这里,我们就明白了主线程在使用handler的条件在创建程序之初就已经具备,所以让用户在主线程中使用handler也方便很多。
1.也可以在子线程创建handler,需要提前prepare looper和自己调用loop。
2.主线程和子线程的区别:主线程的looper创建完后不可以退出,子线程创建的looper是可以退出的,需要自己去prepare()和loop(),主线程的handler环境在进程启动的时候就创建好了。