AsyncTask in Android

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

AsyncTaskIs 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 AsyncTaskexample:

public class MyTask extends AsyncTask<Void, Void, String> {

    @Override
    protected String doInBackground(Void... params) {
        // 后台执行耗时操作
        return "result";
    }

    @Override
    protected void onPostExecute(String result) {
        // 在UI线程更新UI
    }
}

AsyncTaskThree 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, Paramsyes Voidmeans no parameters are passed in, Progressyes Voidmeans no progress updates, Resultand yes Stringmeans returns a string result.

basic structure

AsyncTaskIs 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, Progressand Resultare 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.

AsyncTaskSome static constants are defined, such as SERIAL_EXECUTOR, THREAD_POOL_EXECUTOR, DEFAULT_EXECUTORand so on. These constants indicate AsyncTaskthe type of thread pool that can be used, which SERIAL_EXECUTORis a serial thread pool, THREAD_POOL_EXECUTORa fixed-size thread pool, DEFAULT_EXECUTORand the default thread pool.

Implementation process

AsyncTaskThe execution process can be divided into the following stages:

  1. 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.
  2. doInBackground(Params...): Executed in a background thread, used to perform time-consuming operations, and cannot update the UI.
  3. onProgressUpdate(Progress...): Executed in the UI thread, used to update the progress, such as updating the progress bar.
  4. onPostExecute(Result): Executed in the UI thread, used to perform operations after the completion of the asynchronous task, such as updating the UI, etc.
  5. 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.

 

Guess you like

Origin blog.csdn.net/m0_56366502/article/details/130088523