1205-AsyncTask详解三:AsyncTask对Handler的使用

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,这样onPreExecuteonPostExecute就在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线程中使用,那你的onPreExecuteonPostExecute就不是运行在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方法消失了。

推荐阅读更多精彩内容