关于Asnynck有很多的源码解读,但一些解读现在看来已经不在适用了,比如AsyncTask类必须在UI Thread当中加载,AsyncTask的对象必须在UI Thread当中实例化等一些结论都是基于以前版本的代码来解读的,现在看来已经不是这样的了。
一些结论解读(基于android-23源码):
-
API 16 以前必须在主线程加载 AsyncTask,API 16 以后就不用了。
因为AsyncTask主要目的是在后台执行异步任务,然后和UI线程进行交互,所以需要得到UI线程的Handler,之前的AsyncTask加载时,是得到当前加载线程的Handler,而最新的源码中,总是得到UI线程的Looper来创建和UI交互的Handler。
-
因为每个AsyncTask只能执行一次,多次调用同一个AsyncTask对象会出现异常。但如果要处理多个后台任务,你需要创建多个AsyncTask并执行execute()。
从代码来看,AsyncTask有三种状态,就绪PENDING,运行RUNNING,结束FINISHED,所以只有就绪状态的可以正确执行。可知,每个AsyncTask只能执行一次,所有要想执行多个异步任务,只能新建一个AsyncTask对象。 -
API 4-11 默认是AsnckTask任务并发执行,API11后默认是顺序执行,任务是顺序执行,必须等一个任务结束才能执行下一个。但是可以通过executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)来进行并行执行任务。
THREAD_POOL_EXECUTOR是默认的并行执行任务的线程池,BlockingQueue队列的长度是128。以自己的8核手机为例,其核心线程数是9个,最大线程是17,所能最大加入的任务数是128+17=145,如果超出这个任务数,就会报出RejectExecutionException异常(经过测试)。关于线程池的知识更多可看线程池基础。
这也是为什么新的API将任务默认为串行的原因。 -
** AsyncTask需要在UI线程调用execute()函数 **
可以看出调用execute()函数时调用了onPreExecute(),而onPreExecute()需要在UI线程中执行,所以AsyncTask需要在UI线程调用execute()函数 。(但是如果你不适用onPreExecute在主线程做一些操作的话,execute()可以在任意线程调用)
AsyncTask执行任务的过程原理
AsyncTask的任务执行原理是新建一个有返回值的任务线程FuntureTask和一个Callabler任务,在任务中从doInBackground得到的结果Result通过Handler进行处理,调用onProgress和onPostResult(Result result)关于FuntureTask和Callable更多可看Callable和FutureTask。
AsyncTask的严重问题及替代方案
虽然AsyncTask很好用但却又一些问题需要特别注意,详细内容请看详细解读AsyncTask的黑暗面以及一种替代方案