I wrote a project recently. When refreshing the interface in the foreground, it is necessary to operate the database and perform data operations. Updating data in the UI thread will cause ANR, and the program is very stuck, so AsyncTask is used for background data processing.
introduce
AsyncTask
Is a class for performing asynchronous tasks on a background thread and updating the UI on the main thread. It was introduced in Android API Level 3 and is widely used.
Here is a simple AsyncTask
example:
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
Three generic parameters are defined:
Params
: Specifies the parameter type passed in when the asynchronous task is executed.Progress
: Specifies the type of progress used to update the UI during the execution of the asynchronous task.Result
: Specify the result type returned after the asynchronous task execution is completed.
In the example above, Params
yes Void
means no parameters are passed in, Progress
yes Void
means no progress updates, Result
and yes String
means returns a string result.
basic structure
AsyncTask
Is an abstract class, and its implementation needs to be done by inheriting it and implementing its abstract methods. It is defined as follows:
public abstract class AsyncTask<Params, Progress, Result> {
// ...
}
Among them, Params
, Progress
and Result
are generic parameters, corresponding to the parameter type passed in when the asynchronous task is executed, the type of progress update, and the returned result type.
AsyncTask
Some static constants are defined, such as SERIAL_EXECUTOR
, THREAD_POOL_EXECUTOR
, DEFAULT_EXECUTOR
and so on. These constants indicate AsyncTask
the type of thread pool that can be used, which SERIAL_EXECUTOR
is a serial thread pool, THREAD_POOL_EXECUTOR
a fixed-size thread pool, DEFAULT_EXECUTOR
and the default thread pool.
Implementation process
AsyncTask
The execution process can be divided into the following stages:
onPreExecute()
: Executed in the UI thread, used to perform some preparatory work before the execution of the asynchronous task, such as displaying the progress bar, etc.doInBackground(Params...)
: Executed in a background thread, used to perform time-consuming operations, and cannot update the UI.onProgressUpdate(Progress...)
: Executed in the UI thread, used to update the progress, such as updating the progress bar.onPostExecute(Result)
: Executed in the UI thread, used to perform operations after the completion of the asynchronous task, such as updating the UI, etc.onCancelled()
: Executed in the UI thread, used for operations performed when the asynchronous task is canceled.
application
Create a class that inherits AsyncTask
private class DealDataColor extends AsyncTask {
@Override
protected Object doInBackground(Object[] objects) {
//进行数据处理
return null;
}
}
Call the execute method on the main thread to update the UI
DealDataColor dealDataColor = new DealDataColor();
dealDataColor.execute();
Source code analysis
When using it here, you will find that the created AsyncTask cannot be used again after execute, so why is it designed like this?
Look at the source code:
//这是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;
}
You can see that the value of mStatus is first judged here, which is a value in an enumeration class
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;
This value has been assigned PENDING when the initialization just came in, and if the judgment value is PENDING, an exception will be thrown directly.
execute()
The difference with executeOnExecutor()
the method is that:
execute is fixed thread pool execution. The sDefaultExecutor passed in is static
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
You can customize the thread pool in executeOnExecutor.