preface

In Android, our UI updates are in the main thread. If the main thread is longer than 5s, there is no response. AsyncTask (AsyncTask (AsyncTask, AsyncTask, AsyncTask, AsyncTask, AsyncTask, AsyncTask, AsyncTask, AsyncTask, AsyncTask, AsyncTask, AsyncTask, AsyncTask

Advantages and disadvantages of AsyncTask

advantages

1. Simple operation Encapsulates Thread and Handler for users. The operation is relatively simple. If the user needs to use the AsyncTask, just inherit the AsyncTask and rewrite the doInBackground method in it. If the user wants the execution result of the child thread to be reported to the UI thread, the onPreExecute ( The child thread starts executing) and onPostExectute (which feeds the results of the child thread’s execution back to the UI thread) and onProgressUpdate (which feeds the progress of the child thread back to the UI in real time, usually using a progress bar) can be overridden. 2. The process is controllable

disadvantages

1. If the capacity of the thread pool is insufficient, an exception will be raised. Generally, the size of the thread pool is fixed, which results in a fixed number of concurrent tasks that AsyncTask can perform. Android 1.5 allows AsyncTask to hold only 128 concurrent tasks, and only 10 tasks can be processed at a time (these 10 tasks are queued). This means that if you wait in line before completing 138 tasks, your application will crash. Most of the time, this problem occurs when people load Bitmaps from the network using AsyncTask. The cancell method provided by AsyncTask is just a way of cancelling the flag. It does not actually stop the task until the flag is found. Hold external reference, the outside after the destruction of the task in running, memory not recovered after 3, in the android version 3.0 AsyncTask default is single-threaded So when you add tasks are executed in accordance with the order, if before a task is stuck, behind cannot perform, but system provides a allow a certain number of thread pool for parallel processing, AsyncTask (AsyncTask.THREAD_POOL_EXECUTOR (params)) ¶ Even though the task was executing after the screen was switched, and the progress bar update method was constantly called, and finally the onPostExecute method was executed, nothing changed in the interface.

Since the Activity will be destroyed and rebuilt during vertical and horizontal switching, the reference held by AsyncTask will not be a control of the new Activity, and the new Activity will not change.

One of the solutions

Usage and precautions of AsyncTask

In fact, you can refer to the use of AsyncTask article, which is very good

The use of AsyncTask

package com.xm.studyproject.java; import android.os.AsyncTask; import android.util.Log; import static android.content.ContentValues.TAG; public class UseAsynckTask { public void test() { IAsyncTask iAsyncTask = new IAsyncTask(); iAsyncTask.execute("url1", "url2", "url3"); / / aiming at the problems in using a single thread provides a certain number of thread pool iAsyncTask. ExecuteOnExecutor (AsyncTask THREAD_POOL_EXECUTOR, "url1", "url2", "url3"); } // Generic parameter 1: this place is actually a set // parameter 2: is the progress bar progress is also a set // parameter 3: Private class IAsyncTask extends AsyncTask<String, Integer, String> {//args1 is the argument 1 above // This method is executed in the asynchronous thread, which is the execution of the real task. args1) { int length = args1.length; Log.i(TAG, "doInBackground in:" + args1[0]); Log.i(TAG, "doInBackground in:length:" + length); int times = 0; for (int i = 0; i < 10; i++) { try { Thread.sleep(500); times++; // The onProgressUpdate method is not called to publishProgress(I); // The onProcessUpdate method is executed after the commit} catch (InterruptedException e) {e.printStackTrace(); } } Log.i(TAG, "doInBackground out"); return "over:" + times; } /** * protected void onCancelled() {log. I (TAG, "onCancelled"); Protected void onPostExecute(String args3) {//args3 is the return value of the doInbackground method.  Log.i(TAG, "onPostExecute:" + args3); } @override protected void onPreExecute() {log. I (TAG, "onPreExecute"); } /** * @override protected void onProgressUpdate(Integer) @override protected void onProgressUpdate(Integer) args2) { int length = args2.length; Log.i(TAG, "args2.length:" + length); Log.i(TAG, "onProgressUpdate:" + args2[0]); }}}Copy the code

Pay attention to

Note 1: Remember to call the publishProgress() method immediately on doInBackground() or onProgressUpdate() will not execute. Note 2: Remember to execute asynctask. cancle otherwise there will be memory leaks and other problems

Source code analysis

The AsyncTask source code is relatively simple but does a good job of handling the details

IAsyncTask = new IAsyncTask();

public AsyncTask() { this((Looper) null); } public AsyncTask(@nullable Looper callbackLooper) {// Default is to use the main thread Looper to create a Hanlder mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper); MWorker = new WorkerRunnable<Params, Result>() {public Result call() throws Exception {// Start of the task The task is usually executed on the child thread mTaskInvoked. Set (true); Result result = null; try { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // This method is unexecuted at the moment because the task has not yet started executing result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { postResult(result); } return result; }}; MFuture = new FutureTask<Result>(mWorker) {@override protected void done() {try 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); }}}; //postResultIfNotInvoked method private void postResultIfNotInvoked(Result Result) {Final Boolean Watson invoked = mTaskInvoked.get(); if (! wasTaskInvoked) { postResult(result); }} private Result postResult(Result Result) {@suppressWarnings ("unchecked") // Send to the mainline Message Message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; } 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; New AsyncTaskResult<Result>(this, Result)); Private void finish(Result Result) {if (isCancelled()) {// if the task isCancelled, the onCancelled method is used onCancelled(result); } else {onPostExecute(result) = onPostExecute(result); } mStatus = Status.FINISHED; }Copy the code

Iasynctask. execute(“url1”, “url2”, “url3”);

@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... Params) {// There is another way to execute a thread pool instead of using the execute method executeOnExecutor(sDefaultExecutor, params); } //sDefaultExecutor is a static proxy class that assigns a value to a task queue Ensure that only one sDefaultExecutor application is used. // Volatitle Private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; //SERIAL_EXECUTOR variable SERIAL_EXECUTOR cannot be modified using the static and final staic keyword. The system can reassign public to SERIAL_EXECUTOR by new asyncTasks  static final Executor SERIAL_EXECUTOR = new SerialExecutor(); //SerialExecutor class private static class SerialExecutor implements Executor HTTP: / / https://www.jianshu.com/p/2f633feda6fb / / is mainly for speeding up the production and consumption of data / / is a mutable array provides lots of methods / / thread is unsafe And we adopt the way of the single thread here So use this don't worry about the final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); Runnable mActive; public synchronized void execute(final Runnable r) { //1. Mtasks. offer(new Runnable() {public void run() {try {r.run(); } finally { scheduleNext(); }}}); if (mActive == null) { scheduleNext(); }} protected synchronized void scheduleNext() {if ((mActive = mtasks.poll ())! Thread_pool_executor.execute (mActive); }} //THREAD_POOL_EXECUTOR is a thread pool created ina static code block THREAD_POOL_EXECUTOR; static { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); threadPoolExecutor.allowCoreThreadTimeOut(true); THREAD_POOL_EXECUTOR = threadPoolExecutor; } private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); Private static final int CORE_POOL_SIZE = math.max (2, math.min (CPU_COUNT -1, 4)); // Maximum number of threads CPU *2+1 private static final int MAXIMUM_POOL_SIZE = CPU_COUNT *2+1; Private static final int KEEP_ALIVE_SECONDS = 30;Copy the code

New AsyncTask instances make no sense because SERIAL_EXECUTOR, THREAD_POOL_EXECUTOR, and so on are static final AsyncTask a proxy class that has a serial queue of tasks that can only be executed one by one is SERIAL_EXECUTOR, and a THREAD_POOL_EXECUTOR thread pool that executes tasks

Return to iAsynctask.execute (“url1”, “url2”, “url3”);

   public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
Copy the code

SDefaultExecutor and the creation of the thread pool and the core methods in it and we’re done with the execution of the real method

@MainThread public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... Params) {// If (mStatus! 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; // This is the method onPreExecute() called before the task executes; mWorker.mParams = params; Exec. Execute (mFuture); return this; }Copy the code

Analysis use of FutureTask

There’s nothing to summarize, right

AsyncTask is relatively simple, but the advantages and disadvantages need to be noted and the use of attention

Also, the volatile keyword is volatile. In other words, it guarantees data visibility but does not guarantee atomicity of data operations, so it is used in multi-read scenarios

Refer to the article

Pessimistic lock Optimistic lock (with CAS inside)

The use of Java atomic operations AtomicInteger