Qi:

AsyncTask is an asynchronous message processing mechanism that can be used even if you don’t understand asynchronous messages.

  • Android already encapsulates it in use;
  • It is an abstract class and needs to be inherited.
public abstract class AsyncTask<Params, Progress, Result> { 
 ......
 }
Copy the code

First, advantages and disadvantages:

Advantages:

  • Easy to use: because it is already packaged android, so there is no need for two packaging.
  • You can perform serial or parallel tasks.

Disadvantages:

  • Prone to memory leaks: It is inconsistent with the activity’s life cycle, and doInBackground terminates all the time, regardless of whether the activity’s life cycle ends.
  • The change momentum is relatively large: for example, when some query operations need to modify parameters, they need to end first and then reload again. The problem is with the asynctask.cancel () method, which does not kill background threads recklessly but only sets the status of AsyncTask to “canceled.”
  • There are too many differences between versions.

Two, source code understanding:

AsyncTask has two thread pools (SerialExecutor and THREAD_POOL_EXECUTOR) and one Handler (InternalHandler). The thread pool SerialExecutor is used to queue tasks. The thread pool THREAD_POOL_EXECUTOR is used to actually execute the task, and InternalHandler is used to switch the execution environment from the thread pool to the main thread.

Rewrite method:

  • DoInBackground: It is performed in the background. Time-consuming operations are performed here and UI cannot be operated directly.
  • OnPostExecute: receives the execution result of the thread and displays the execution result on the UI.
  • OnPreExecute: Operations performed before executing a thread task.
  • OnProgressUpdate: Displays the progress of the main thread.
  • Execute: Triggers the execution of asynchronous tasks (manually invoked)

public static final Executor THREAD_POOL_EXECUTOR; Static {ThreadPoolExecutor ThreadPoolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), sThreadFactory); threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy); THREAD_POOL_EXECUTOR = threadPoolExecutor; }Copy the code

When the class is loaded, a thread pool is generated to perform tasks.

public AsyncTask(@Nullable Looper callbackLooper) { mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper); mWorker = new WorkerRunnable<Params, Result>() {// Rewrite call to get the Result after executing the child thread task public Result Call () throws Exception {mTaskInvoked. Set (true); Result result = null; Try {/ / set the Process priority. SetThreadPriority (Process. THREAD_PRIORITY_BACKGROUND); // Calling the doInBackground method executes result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { postResult(result); } return result; }}; MFuture = new FutureTask<Result>(mWorker) {// Done thread after execution @override protected Void done() {try {// Obtain the result by the get method postResultIfNotInvoked(get()); } catch (InterruptedException e) { android.util.Log.w(LOG_TAG, e); } catch (ExecutionException e) { throw new RuntimeException("An error occurred while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); }}}; }Copy the code

In the constructor of AsyncTask, there is a mWorker which is a Callable among the three implementation methods of derivation and thread, and FutureTask is used to obtain the result.

When we call execute manually:

@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); } @MainThread 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; // Move the task to the thread pool and execute exec.execute(mFuture); return this; }Copy the code

The AsyncTask execution state is determined, onPreExecute is executed for some initialization, and the task is executed from the thread pool.

private void postResultIfNotInvoked(Result result) { final boolean wasTaskInvoked = mTaskInvoked.get(); if (! wasTaskInvoked) { postResult(result); } } private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }Copy the code

The obtained results are sent to the Ui thread via InternalHandler

private static class InternalHandler extends Handler { public InternalHandler(Looper looper) { super(looper); } @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) @Override public void handleMessage(Message msg) { AsyncTaskResult<? > result = (AsyncTaskResult<? >) msg.obj; switch (msg.what) { case MESSAGE_POST_RESULT: // There is only one result result.mTask.finish(result.mData[0]); break; case MESSAGE_POST_PROGRESS: result.mTask.onProgressUpdate(result.mData); break; } } } private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }Copy the code

If not, call onPostExecute and send the result to the UI thread. MStatus is set to FINISHED, indicating that the current AsyncTask is FINISHED.

Reference blog:

The principle of AsyncTask

A memory leak