🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
#### 1.2.1 AsyncTask [AsyncTask](https://www.androidos.net.cn/android/6.0.1_r16/xref/frameworks/base/core/java/android/os/AsyncTask.java)是一种**轻量级的异步任务类**,它**可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UI**。从实现上来说,**AsyncTask封装了Thread和Handler,通过AsyncTask可以更加方便地执行后台任务以及在主线程中访问UI,但是AsyncTask并不适合进行特别耗时的后台任务,对于特别耗时的任务来说,建议使用线程池**。 **AsyncTask是一个抽象的泛型类**,它**提供了Params、Progress和Result这三个泛型参数(*注意这里的泛型参数,要记住各自的含义,具体的参数数据类型,具体分析*)**,其中 1. **Params表示参数的类型**, 2. **Progress表示后台任务的执行进度的类型**, 3. 而**Result则表示后台任务的返回结果的类型**, **如果AsyncTask确实不需要传递具体的参数,那么这三个泛型参数可以用Void来代替**。AsyncTask这个类的声明如下所示。 ``` public abstract class AsyncTask<Params, Progress, Result>。 ``` ![](https://box.kancloud.cn/2015-12-01_565da6861a2c6.jpg) AsyncTask提供了4个核心方法,它们的含义如下所示。 * (1)`onPreExecute()`,在**主线程中执行**,在**异步任务执行之前,此方法会被调用,一般可以用于做一些准备工作**。 * (2)`doInBackground(Params...params)`,在**线程池中执行**,此方法**用于执行异步任务**,params参数表示异步任务的输入参数。**在此方法中可以通过publishProgress方法来更新任务的进度,publishProgress方法会调用onProgressUpdate方法。另外此方法需要返回计算结果给onPostExecute方法**。 * (3)`onProgressUpdate(Progress...values`),在**主线程中执行**,**当后台任务的执行进度发生改变时此方法会被调用**。 * (4)`onPostExecute(Result result)`,在**主线程中执行**,主要**进行UI的更新操作**,在**异步任务执行之后,此方法会被调用**,其中**result参数是后台任务(doInBackground中进行的异步任务)的返回值,即doInBackground的返回值**。 ![](https://box.kancloud.cn/2015-12-01_565da68711c04.jpg) 上面这几个方法,onPreExecute先执行,接着是doInBackground,最后才是onPostExecute。除了上述四个方法以外,**AsyncTask还提供了onCancelled()方法,它同样在主线程中执行,当异步任务被取消时,onCancelled()方法会被调用,这个时候onPostExecute则不会被调用**。下面提供一个典型的示例,如下所示。 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> { protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; for (int i = 0; i < count; i++) { totalSize += Downloader.downloadFile(urls[i]); publishProgress((int) ((i / (float) count)*100)); // Escape early if cancel() is called if (isCancelled()) break; } return totalSize; } protected void onProgressUpdate(Integer... progress) { setProgressPercent(progress[0]); } protected void onPostExecute(Long result) { showDialog("Downloaded " + result + " bytes"); } } 在上面的代码中,**实现了一个具体的AsyncTask类,这个类主要用于模拟文件的下载过程**,它的**输入参数类型为URL,后台任务的进程参数为Integer,而后台任务的返回结果为Long类型**。 注意到doInBackground和onProgressUpdate方法它们的参数中均包含…的字样,在Java中…表示参数的数量不定(**就是可变参数**),它是一种数组型参数,…的概念和C语言中的…是一致的。当要执行上述下载任务时,可以通过如下方式来完成: ``` new DownloadFilesTask().execute(url1, url2, url3); ``` 在DownloadFilesTask中, * `doInBackground`用来**执行具体的下载任务并通过publishProgress方法来更新下载的进度,同时还要判断下载任务是否被外界取消了。当下载任务完成后,doInBackground会返回结果,即下载的总字节数**。 需要注意的是,**doInBackground是在线程池中执行的**。 * `onProgressUpdate`用于**更新界面中下载的进度,它运行在主线程,当publishProgress被调用时,此方法就会被调用**。 * 当**下载任务完成后**,**onPostExecute方法就会被调用,它也是运行在主线程中**,这个时候我们**就可以在界面上做出一些提示,比如弹出一个对话框告知用户下载已经完成**。 AsyncTask在具体的使用过程中也是有一些条件限制的,主要有如下几点: * (1)**AsyncTask的类必须在主线程中加载**,这就意味着**第一次访问AsyncTask必须发生在主线程,当然这个过程在Android 4.1及以上版本中已经被系统自动完成**。在Android 5.0的源码中,可以查看ActivityThread的main方法,它会调用AsyncTask的init方法,这就满足了**AsyncTask的类必须在主线程中进行加载**这个条件了。至于为什么必须要满足这个条件,在11.2.2节中会结合AsyncTask的源码再次分析这个问题。 * (2)**AsyncTask的对象必须在主线程中创建**。 * (3)**execute方法必须在UI线程调用**。 * (4)**不要在程序中直接调用`onPreExecute()`、`onPostExecute`、`doInBackground`和`onProgressUpdate`方法**。 * (5)**一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常**。 * (6)在Android 1.6之前,AsyncTask是串行执行任务的,Android 1.6的时候AsyncTask开始采用线程池里处理并行任务,但是从**Android 3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务**。**尽管如此,在Android 3.0以及后续的版本中,我们仍然可以通过AsyncTask的executeOnExecutor方法来并行地执行任务**。 ![](https://box.kancloud.cn/2015-12-01_565da6887ac4b.jpg) #### 参考文章: [Android AsyncTask 源码解析](https://blog.csdn.net/lmj623565791/article/details/38614699?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159594982819724845029718%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=159594982819724845029718&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_blog_v1-1-38614699.pc_v2_rank_blog_v1&utm_term=AsyncTask&spm=1018.2118.3001.4187) [Android AsyncTask完全解析,带你从源码的角度彻底理解](https://blog.csdn.net/guolin_blog/article/details/11711405?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159594993219195162550355%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=159594993219195162550355&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_blog_v1-1-11711405.pc_v2_rank_blog_v1&utm_term=AsyncTask&spm=1018.2118.3001.4187) [Android ListView异步加载图片乱序问题,原因分析及解决方案](https://blog.csdn.net/guolin_blog/article/details/45586553?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159595154619195188456825%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=159595154619195188456825&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_blog_v1-2-45586553.pc_v2_rank_blog_v1&utm_term=AsyncTask&spm=1018.2118.3001.4187) [Android高效加载大图、多图解决方案,有效避免程序OOM](https://blog.csdn.net/guolin_blog/article/details/9316683?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159594993219195162550355%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=159594993219195162550355&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_blog_v1-3-9316683.pc_v2_rank_blog_v1&utm_term=AsyncTask&spm=1018.2118.3001.4187) [Android应用程序线程消息循环模型分析](https://blog.csdn.net/Luoshengyang/article/details/6905587?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159595740419724839261754%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=159595740419724839261754&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_blog_v1-1-6905587.pc_v2_rank_blog_v1&utm_term=AsyncTask&spm=1018.2118.3001.4187)