AsyncTask source code analysis, asynctask source code

Source: Internet
Author: User

AsyncTask source code analysis, asynctask source code
For the usage of AsyncTask, see the previous blog "AsyncTask resumable upload". This article only parses the source code of AsyncTask. AsyncTask.exe cute method:

1     public final AsyncTask<Params, Progress, Result> execute(Params... params) {2         return executeOnExecutor(sDefaultExecutor, params);3     }
The executeOnexecute method is called directly in the execute method. AsyncTask.exe cuteOnexecute method:
 1     public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, 2             Params... params) { 3         if (mStatus != Status.PENDING) { 4             switch (mStatus) { 5                 case RUNNING: 6                     throw new IllegalStateException("Cannot execute task:" 7                             + " the task is already running."); 8                 case FINISHED: 9                     throw new IllegalStateException("Cannot execute task:"10                             + " the task has already been executed "11                             + "(a task can be executed only once)");12             }13         }14         mStatus = Status.RUNNING;15         onPreExecute();16         mWorker.mParams = params;17         exec.execute(mFuture);18         return this;19     }
Row 3-13 checks the status of AsyncTask. If the status is not PENDING, an exception is thrown. This is why an AsyncTask can only be executed once. Line 14 changes the status to RUNNING, indicating that the task is RUNNING. Then, call the onPreExecute () method of AsyncTask. The following code shows that AsyncTask has three states: PENDING (not RUNNING), RUNNING (RUNNING), and FINISHED (RUNNING ).
 1     public enum Status { 2         /** 3          * Indicates that the task has not been executed yet. 4          */ 5         PENDING, 6         /** 7          * Indicates that the task is running. 8          */ 9         RUNNING,10         /**11          * Indicates that {@link AsyncTask#onPostExecute} has finished.12          */13         FINISHED,14     }
FutureTask code:
1 public class FutureTask <V> implements RunnableFuture <V> {2 ...... 3 // constructor to pass in a Callable object 4 public FutureTask (Callable <V> callable) {5 if (callable = null) 6 throw new NullPointerException (); 7 this. callable = callable; 8 this. state = NEW; // ensure visibility of callable 9} 10 public void run () {11 if (state! = NEW | 12! UNSAFE. compareAndSwapObject (this, runnerOffset, 13 null, Thread. currentThread () 14 return; 15 try {16 Callable <V> c = callable; 17 if (c! = Null & state = NEW) {18 V result; 19 boolean ran; 20 try {21 result = c. call (); // callable is called here. call () method 22 ran = true; 23} catch (Throwable ex) {24 result = null; 25 ran = false; 26 setException (ex); 27} 28 if (ran) 29 set (result); 30} 31} finally {32 // runner must be non-null until state is settled to33 // prevent concurrent callto run () 34 runner = null; 35 // state must be re-read after nulling runner to prevent36 // leaked interrupts37 int s = state; 38 if (s> = INTERRUPTING) 39 handlePossibleCancellationInterrupt (s ); 40} 41} 42 ...... 43}

 

AsyncTask constructor:
1 public abstract class AsyncTask <Params, Progress, Result> {2 ...... 3/** 4 * Creates a new asynchronous task. this constructor must be invoked on the UI thread. 5 */6 public AsyncTask () {7 mWorker = new WorkerRunnable <Params, Result> () {8 public Result call () throws Exception {9 mTaskInvoked. set (true); 10 Process. setThreadPriority (Process. THREAD_PRIORITY_BACKGROUND); 11 // noinspection unchecked12 return postResult (doInBackground (mParams); 13} 14 }; 15 // when creating the FutureTask object, mWorker is input as Callable16 mFuture = new FutureTask <Result> (mWorker) {17 @ Override18 protected void done () {19 try {20 postResultIfNotInvoked (get (); 21} catch (InterruptedException e) {22 android. util. log. w (LOG_TAG, e); 23} catch (ExecutionException e) {24 throw new RuntimeException ("An error occured while executing doInBackground ()", 25 e. getCause (); 26} catch (CancellationException e) {27 postResultIfNotInvoked (null); 28} 29} 30}; 31} 32 ...... 33}

 

From the source code of FutureTask, we can see that the run () method calls c. call (), and when a FutureTask is created in AsyncTask, mWorker is passed in, so the FutureTask. c. call () calls the call () method of the mWorker object. In AsyncTask, mWorker overwrites the call method, that is, the above 8-14 rows, So c. call () will be executed to mWorker. call () method. In the call method, line 11 sets the thread priority to the background thread, so that when multiple threads are concurrent, the CPU time allocated by many irrelevant threads will be reduced, which is conducive to the processing of the main thread. In the next 11 rows, the doInBackground (mParams) method is executed. We usually rewrite this method to implement business logic operations. Then execute the postResult method and return the result to FutureTask (because this call method is called by the FutureTask. run method, the result must be returned to the FutureTask. run method ). Here let's take a look at postResult:
1     private Result postResult(Result result) {2         @SuppressWarnings("unchecked")3         Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,4                 new AsyncTaskResult<Result>(this, result));5         message.sendToTarget();6         return result;7     }

Here, the sHandler is the InternalHandler object.
 1     private static class InternalHandler extends Handler { 2         @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) 3         @Override 4         public void handleMessage(Message msg) { 5             AsyncTaskResult result = (AsyncTaskResult) msg.obj; 6             switch (msg.what) { 7                 case MESSAGE_POST_RESULT: 8                     // There is only one result 9                     result.mTask.finish(result.mData[0]);10                     break;11                 case MESSAGE_POST_PROGRESS:12                     result.mTask.onProgressUpdate(result.mData);13                     break;14             }15         }16     }

The 9th lines of code show that the AsyncTask finish method will be executed. The Code is as follows:
1     private void finish(Result result) {2         if (isCancelled()) {3             onCancelled(result);4         } else {5             onPostExecute(result);6         }7         mStatus = Status.FINISHED;8     }

Finish is used to execute the onCancelled method if the task is canceled. if the task is not canceled, the onPostExecute method is executed normally. (This is why the task is called the cancel method, does not execute onPostExecute ). Finally, mark the task status as FINISHED. As mentioned above, mWorker. call will return the execution result to the FutureTask. run () method and continue to execute it. Let's look at the FutureTask. run method (20-30 rows) again ):
 1 boolean ran; 2 try { 3      result = c.call(); 4      ran = true; 5 } catch (Throwable ex) { 6      result = null; 7      ran = false; 8      setException(ex); 9 }10 if (ran)11      set(result);

The code above shows that after c. call is executed, the set (result) method is executed.
1     protected void set(V v) {2         if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {3             outcome = v;4             UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state5             finishCompletion();6         }7     }

The finishCompletion () method is executed.
 1     private void finishCompletion() { 2         // assert state > COMPLETING; 3         for (WaitNode q; (q = waiters) != null;) { 4             if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) { 5                 for (;;) { 6                     Thread t = q.thread; 7                     if (t != null) { 8                         q.thread = null; 9                         LockSupport.unpark(t);10                     }11                     WaitNode next = q.next;12                     if (next == null)13                         break;14                     q.next = null; // unlink to help gc15                     q = next;16                 }17                 break;18             }19         }20         done();21         callable = null;        // to reduce footprint22     }

If you see 21 lines of code, the done () method of FutureTask will be executed. This method is overwritten when initializing the FutureTask object in the AsyncTask constructor.
 1     mFuture = new FutureTask<Result>(mWorker) { 2             @Override 3             protected void done() { 4                 try { 5                     postResultIfNotInvoked(get()); 6                 } catch (InterruptedException e) { 7                     android.util.Log.w(LOG_TAG, e); 8                 } catch (ExecutionException e) { 9                     throw new RuntimeException("An error occured while executing doInBackground()",10                             e.getCause());11                 } catch (CancellationException e) {12                     postResultIfNotInvoked(null);13                 }14             }15         };
Here, we mainly verify whether postResult is called. If postResult is not called, it is a good operation because it has been called in the previous mWorker. call method. By the way, to update the UI in the doInBackground method of AsyncTask, call the publishProgress method of AsyncTask:
1     protected final void publishProgress(Progress... values) {2         if (!isCancelled()) {3             sHandler.obtainMessage(MESSAGE_POST_PROGRESS,4                     new AsyncTaskResult<Progress>(this, values)).sendToTarget();5         }6     }

The publishProgress method will eventually call the onProgressUpdate method of AsyncTask through sHandler. Generally, if we need to obtain the progress, we need to override the onProgressUpdate of AsyncTask. All right, the source code of AsyncTask is also analyzed. Summarize the precautions for using Asynctask again:

1. the instance of the asynchronous task must be created in the UI thread.

2. The execute (Params... params) method must be called in the UI thread.

3. Do not manually call the onPreExecute (), doInBackground (Params... params), onProgressUpdate (Progress... values), onPostExecute (Result result) methods.

4. You cannot change the UI component information in doInBackground (Params... params.

5. A task instance can only be executed once. If it is executed for the second time, an exception is thrown.

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.