AsyncTask是对线程池和Handler的封装。以API 23源码为例,看它是怎样使用Handler的
private static InternalHandler sHandler;
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@Override
public void handleMessage(Message msg) {
... ...
}
}
Handler使用了主线程的Looper,这样onPreExecute
和onPostExecute
就在UI线程执行,很完美。
但是看一下API 21的源码
private static final InternalHandler sHandler = new InternalHandler();
private static class InternalHandler extends Handler {
@Override
public void handleMessage(Message msg) {
... ...
}
}
会发现没有在构造方法中获取主线程Looper,而是使用了默认的,而默认使用的是当前线程的Looper。如果你是在主线程中使用AsyncTask,那倒没什么问题,可是要是在非UI线程中使用,那你的onPreExecute
和onPostExecute
就不是运行在UI线程里,那会直接导致崩溃。这就是常说的 AsyncTask必须在主线程创建 的原因。
另外,AsyncTask里面的这个Handler是一个静态的类变量,也就是说它是在类加载的时候创建的;如果在你的APP进程里面,以前从来没有使用过AsyncTask,然后在子线程使用AsyncTask的相关变量,那么导致静态Handler初始化,如果在API 16以下,就会出现上面同样的问题;这就是 AsyncTask必须在主线程初始化 的原因。这一点实际是由框架层来保证的。
Android 4.1(API 16)以后,和6.0(API 23)以前,在APP主线程ActivityThread的main函数里面,直接调用了AscynTask.init
函数确保这个类是在主线程初始化的;另外,init这个函数里面获取了InternalHandler
的Looper,由于是在主线程执行的,因此,AsyncTask的Handler用的也是主线程的Looper。这个问题从而得到彻底的解决。
/** @hide Used to force static handler to be created. */
public static void init() {
sHandler.getLooper();
}
而在API 23(6.0)以后,AsyncTask的init方法消失了。