[TOC]

概述

由于Android的特性,如果要执行耗时操作,则必须方法子线程中执行。如果在主线程中执行耗时操作那么会导致应用程序无法及时响应。除了Thread可以开启子线程外,Android中扮演线程角色的有很多。比如:AsyncTask和IntentService(开启任务线程执行耗时操作),同时HandlerThread(含有handler的Thread)也是一种特殊的线程。本篇文章主要介绍AsyncTask,一个执行异步任务的类,底层是采用线程池实现的。而IntentService和HandlerThread。他们的底层则直接使用了线程。

一、Android中的线程

在操作系统中,线程是操作系统调度的最小单元,同时线程又是一种受限的系统资源,即线程不可能无限制地产生,并且线程的创建和销毁都会有相应的开销。当系统中存在大量的线程时,系统会通过会时间片轮转的方式调度每个线程,因此线程不可能做到绝对的并行。

如果在一个进程中频繁地创建和销毁线程,显然不是高效的做法。正确的做法是采用线程池,一个线程池中会缓存一定数量的线程,通过线程池就可以避免因为频繁创建和销毁线程所带来的系统开销。关于线程池的理解,参考Java线程池详解,Android同样适用。

二、AsyncTask简介

AsyncTask是一个抽象类,它是由Android封装的一个轻量级异步类(轻量体现在使用方便、代码简洁),它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UI。从实现上来讲,AsyncTask封装了Thread和Handler。通过AsyncTask可以更加方便的执行后台任务以及在主线程中访问UI。但是AsyncTask并不适合进行特别耗时的后台任务。这种情况下还是建议使用线程池比较好一些。

AsyncTask的内部封装了两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler)。

其中SerialExecutor线程池用于任务的排队,让需要执行的多个耗时任务,按顺序排列,THREAD_POOL_EXECUTOR线程池才真正地执行任务,InternalHandler用于从工作线程切换到主线程。

1.AsyncTask的泛型参数

AsyncTask的类声明如下:

1
public abstract class AsyncTask<Params, Progress, Result>

有四个核心方法:

1
2
3
4
5
6
7
onPreExcute()

doInBackground()

onProgressUpgrade()

onPostExcute(Result result) //在主线程执行,在异步任务执行之后此方法会被执行,将result参数是后台任务的返回值,即doInBackground()的返回值

提炼总结

AsyncTask中有两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler),其中线程池SerialExecutor用于任务的排队,而线程池THREAD_POOL_EXECUTOR用于真正地执行任务,InternalHandler用于将执行环境从线程池切换到主线程。

sHandler是一个静态的Handler对象,为了能够将执行环境切换到主线程,这就要求sHandler这个对象必须在主线程创建。由于静态成员会在加载类的时候进行初始化,因此这就变相要求AsyncTask的类必须在主线程中加载,否则同一个进程中的AsyncTask都将无法正常工作。