Android中的线程形态
本节将对Android中的线程形态做一个全面的介绍,除了传统的Thread以外,还包含了AsyncTask,HandlerThread以及IntentService,这三者的底层实现也是线程,但是他们具有特殊的表现形式,同时在使用上也各有优缺点,下面从源码的角度来分析AsyncTask的执行过程。
一、AsyncTask
AsyncTask是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UI。从实现上来说,AsyncTask封装了Thread和Handler,通过AsyncTask我们更加方便的执行后台任务以及在主线程中访问UI,但是AsyncTask并不适合进行特别耗时的后台任务,对于特别耗时的任务来说,建议使用线程池。
AsyncTask是一个抽象的泛型类,他提供了Params,Progress和Result这三个泛型参数,其中Params表示参数的类型,Progress表示后台任务的执行进度,Result表示后台任务的返回结果的类型,如果AsyncTask确实不需要传递具体的参数,那么这三个泛型可以用Void来代替。AsyncTask这个类的声明如下所示。
public abstract class AsyncTask<Params, Progress, Result>
AsyncTask提供了4个核心方法,它们的含义如下所示。
- onPreExecute()
在主线程执行,在异步任务执行之前被调用,一般可以用于做一些准备工作。
- doInBackground(Params… params)
在线程池中执行,此方法用于执行异步任务,params参数表示异步任务的输入参数。在此方法中可以通过publishProgress方法来更新任务的进度,publishProgress会调用onProgressUpdate方法。此外此方法需要返回计算结果给onPostExecute方法。
- onProgressUpdate(Progress… values)
在主线程执行,当后台任务的执行进度发生改变时此方法会被调用。
- onPostExecute(Result result)
在主线程中执行,在异步任务结束之后,此方法被调用,其中result参数是后台任务的返回值,即DoInBackground的返回值。
上面几个方法,onPreExecute先执行,接着是doInBackground,最后才是onPostExecute。除了上述四个方法以外,AsyncTask还提供了一个onCancelled()方法,它同样在主线程中执行,当异步任务被取消时,onCancelled就会被调用,这个时候onPostExecute就不会被调用。下面提供一个典型的示例(这个示例就是源码中的)
class DownloadTask extends AsyncTask<URL,Integer,Long>{
@Override
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < totalSize; i++) {
totalSize += DownLoad.downloadFile(urls[i]);
publicProgress((int)((i / (float)count)*100));
if(isCancelled()){
break;
}
}
return totalSize;
}
@Override
protected void onProgressUpdate(Integer... values) {
setProgressPercent(values[0]);
}
@Override
protected void onPostExecute(Long aLong) {
showDialog(aLong);
}
}
AsyncTask在使用的过程中也有一些条件限制的,主要有如下几点:
- 1、AsyncTask的类必须在主线程加载,也就意味着第一次访问AsyncTask必须发生在主线程,当然这个过程在Android4.1之后已经被系统自动完成了,在Android5.0的源码中,可以看到ActivityThread的main方法,它会调用AsyncTask的init方法,这就满足了AsyncTask的类必须在主线程中加载这个条件了。
- 2、AsyncTask的对象必须在主线程创建。
- 3、execute方法必须在UI线程调用。
- 4、不要再程序中直接使用onPreExecute、onPostExecute、DoInBackground和onProgressUpdate方法。
- 5、一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会运行时异常。
- 6、在Android1.6之前,AsyncTask是串行执行任务的,Android1.6之后开始采用线程池并行处理,但是从Android3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行任务。尽管如此,在Android3.0以及以后的版本中,我们也可以通过AsyncTask的executteOnExecutor方法来并行的执行任务。
二、AsyncTask的工作原理
为了分析AsyncTask的工作原理,我们从它的execute方法开始分析
android.os.AsyncTask#execute
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
//private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
return executeOnExecutor(sDefaultExecutor, params);
}
android.os.AsyncTask#executeOnExecutor
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.