近期写了一个项目,在前台刷新界面的时候需要操作数据库,进行数据操作,在UI线程更新数据会导致ANR,程序十分卡,因此用了AsyncTask进行后台数据处理。
介绍
AsyncTask
是一个用于在后台线程执行异步任务并在主线程更新UI的类。它是在Android API Level 3中引入的,并被广泛使用。
下面是一个简单的AsyncTask
的示例:
public class MyTask extends AsyncTask<Void, Void, String> {
@Override
protected String doInBackground(Void... params) {
// 后台执行耗时操作
return "result";
}
@Override
protected void onPostExecute(String result) {
// 在UI线程更新UI
}
}
AsyncTask
定义了三个泛型参数:
Params
:指定异步任务执行时传入的参数类型。Progress
:指定异步任务执行过程中用于更新UI的进度的类型。Result
:指定异步任务执行完成后返回的结果类型。
在上面的示例中,Params
是Void
,即没有传入参数,Progress
是Void
,即没有进度更新,Result
是String
,即返回一个字符串结果。
基本结构
AsyncTask
是一个抽象类,它的实现需要通过继承它并实现其抽象方法来完成。它的定义如下:
public abstract class AsyncTask<Params, Progress, Result> {
// ...
}
其中,Params
、Progress
和Result
是泛型参数,分别对应异步任务执行时传入的参数类型、进度更新的类型和返回的结果类型。
AsyncTask
定义了一些静态常量,如SERIAL_EXECUTOR
、THREAD_POOL_EXECUTOR
、DEFAULT_EXECUTOR
等。这些常量表示了AsyncTask
可以使用的线程池类型,其中SERIAL_EXECUTOR
是一个串行线程池,THREAD_POOL_EXECUTOR
是一个固定大小的线程池,DEFAULT_EXECUTOR
是默认的线程池。
执行流程
AsyncTask
的执行流程可以分为以下几个阶段:
onPreExecute()
:在UI线程中执行,用于在异步任务执行前进行一些准备工作,例如显示进度条等。doInBackground(Params...)
:在后台线程中执行,用于执行耗时操作,不可以更新UI。onProgressUpdate(Progress...)
:在UI线程中执行,用于更新进度,例如更新进度条等。onPostExecute(Result)
:在UI线程中执行,用于执行异步任务完成后的操作,例如更新UI等。onCancelled()
:在UI线程中执行,用于在异步任务被取消时执行的操作。
应用
创建一个类继承AsyncTask
private class DealDataColor extends AsyncTask {
@Override
protected Object doInBackground(Object[] objects) {
//进行数据处理
return null;
}
}
在主线程调用execute方法更新UI
DealDataColor dealDataColor = new DealDataColor();
dealDataColor.execute();
源码分析
这里使用的时候会发现,创建后的AsyncTask在execute后就不能再次使用了,那么为什么会这样设计呢?
看看源码:
//这是execute方法的实现
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
//在execute里调用了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.mParams = params;
exec.execute(mFuture);
return this;
}
可以看到这里先判断mStatus的值,这个值是一个枚举类里的值
public enum Status {
/**
* Indicates that the task has not been executed yet.
*/
PENDING,
/**
* Indicates that the task is running.
*/
RUNNING,
/**
* Indicates that {@link AsyncTask#onPostExecute} has finished.
*/
FINISHED,
}
private volatile Status mStatus = Status.PENDING;
这个值在初始化刚进来的时候已经被赋予了PENDING,判断值如果是不是PENDING直接就会抛出异常。
execute()
和 executeOnExecutor()
方法的区别在于:
execute是固定了线程池执行。里面传入的sDefaultExecutor 是静态的
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
executeOnExecutor里面可以自定义线程池。