Source code analysis Android AsyncTask

Source: Internet
Author: User

Android UI operations are thread-unsafe. To perform UI operations in child thread red, you need to use the Handler provided by Android. The AsyncTask provided by Android is actually an encapsulation of Handler, so that we can update the UI element in the Child thread. AsyncTask is a generic class in the format of AsyncTask. . The three parameters are used as follows:

1. Params

The three parameters are used as follows:
1. Params
Parameters that need to be passed in when executing AsyncTask can be used in background tasks.
2. Progress
If you need to display the current progress on the page when executing background tasks, use the generic type specified here as the progress unit.
3. Result
After the task is executed, if you need to return the result, use the generic type specified here as the return value type.

The usage of AsyncTask in Android SDK is as follows:

 private class DownloadFilesTask extends AsyncTask(URL, Integer, Long) {      protected Long doInBackground(URL... urls) {          int count = urls.length;          long totalSize = 0;          for (int i = 0; i < count; i++) {              totalSize += Downloader.downloadFile(urls[i]);              publishProgress((int) ((i / (float) count)  100));              // Escape early if cancel() is called              if (isCancelled()) break;          }          return totalSize;      }       protected void onProgressUpdate(Integer... progress) {          setProgressPercent(progress[0]);      }       protected void onPostExecute(Long result) {          showDialog("Downloaded " + result + " bytes");      }  } new DownloadFilesTask().execute(url1, url2, url3);

AsyncTask is an abstract class. There are four methods to be rewritten. The Calling process of these four methods is as follows:
The onPreExecute () method is called between the execution of background tasks for initialization on some interfaces.
All the code in step 1. doInBackground (Params...) will run in the Child thread. We should process all time-consuming tasks here. Once the task is completed, the return statement can be used to return the execution result of the task. To update the UI element, for example, to feedback the Progress of the current task, you can call publishProgress (Progress.
Step 2. when publishProgress (Progress...) is called in the background task ...) method, onProgressUpdate (Progress ...) the method will be called soon, and the parameters carried in the method will be passed in the background task. In this method, you can perform operations on the UI, and use the values in the parameters to update the interface elements accordingly.
Step 2. When the background task is completed and returned using the return statement, onPostExecute (Result) will be called soon. Here you can
Perform UI operations.

Source code of AsyncTask
When I used AsyncTask, I never understood why onProcessUpdate was called on a regular basis. Later, we wanted to implement a Scheduled Update task progress function in our work. We used a Handler to send messages to ourselves for scheduled refresh. Now I have studied the implementation principle of AsyncTask, and found that it also uses Handler to send messages to itself to implement regular refresh. When I use the Android 4.4 source code, if you can understand the implementation principle of AsyncTask, you can also write a simple AsyncTask by yourself.
First look at the constructor: note that constructor must be called in the UI.

   /**     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.     */    public AsyncTask() {        mWorker = new WorkerRunnable
 
  () {            public Result call() throws Exception {                mTaskInvoked.set(true);                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                //noinspection unchecked                return postResult(doInBackground(mParams));            }        };        mFuture = new FutureTask
  
   (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 occured while executing doInBackground()",                            e.getCause());                } catch (CancellationException e) {                    postResultIfNotInvoked(null);                }            }        };    }
  
 
This function has initially made two variables: mWorker and mFuture. MWorker is a Callable object, and mFuture is an object that implements Runnable and Future. Execute (Params) is called to start AsyncTask)
    public final AsyncTask
 
   execute(Params... params) {        return executeOnExecutor(sDefaultExecutor, params);    }
 
This method calls the executeOnExecutor () method. The Code is as follows:

    public final AsyncTask
 
   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;    }
 
The Supervisor First sets the running state, then calls onpreexecute, and finally calls exec.exe cute (mFuture). The input exec is sDefaultExecutor, And the sDefaultExecutor is a SerialExecutor object. The source code is as follows:

private static class SerialExecutor implements Executor {        final ArrayDeque
 
   mTasks = new ArrayDeque
  
   ();        Runnable mActive;        public synchronized void execute(final Runnable r) {            mTasks.offer(new Runnable() {                public void run() {                    try {                        r.run();                    } finally {                        scheduleNext();                    }                }            });            if (mActive == null) {                scheduleNext();            }        }        protected synchronized void scheduleNext() {            if ((mActive = mTasks.poll()) != null) {                THREAD_POOL_EXECUTOR.execute(mActive);            }        }    }
  
 
When sdefaultexecutor.exe cute (runnable) is used, this method uses an ArrayDeque to save runnable, which will be called when appropriate. When mActivity is run for the first time, it is null. Therefore, the scheduleNext () method is called. In this method, the value is taken from the header of the queue and assigned to the mActive object. Then, THREAD_POOL_EXECUTOR is called to execute the retrieved Runnable object. Here, a try finally code block is used and the scheduleNext () method is called in finally. Each time a task is executed, the next task is executed, serialExecutor imitates the effect of a single thread pool. If we start many tasks quickly, only one thread is executing at a time, and the rest are waiting.

The object passed in by sDefaultExecutor.exe cute (Runnable) is mFuture, and mFuture is a FutureTask object. Its constructor is as follows:

 public FutureTask(Callable
 
   callable) {        if (callable == null)            throw new NullPointerException();        this.callable = callable;        this.state = NEW;       // ensure visibility of callable    }
 
According to the AsyncTask constructor, callable in FutureTask is an mWorkder object. The run () Code of FutureTask is as follows:
    public void run() {        if (state != NEW ||            !UNSAFE.compareAndSwapObject(this, runnerOffset,                                         null, Thread.currentThread()))            return;        try {            Callable
 
   c = callable;            if (c != null && state == NEW) {                V result;                boolean ran;                try {                    result = c.call();                    ran = true;                } catch (Throwable ex) {                    result = null;                    ran = false;                    setException(ex);                }                if (ran)                    set(result);            }        } finally {            // runner must be non-null until state is settled to            // prevent concurrent calls to run()            runner = null;            // state must be re-read after nulling runner to prevent            // leaked interrupts            int s = state;            if (s >= INTERRUPTING)                handlePossibleCancellationInterrupt(s);        }    }
 
Therefore, mWorker's call () will be called (). The call () of mWorker is located in the constructor of AsyncTask. You can find that it first calls doInBackgroud (Params) and then calls postResult (). postResult (Result). The source code is as follows:

    private Result postResult(Result result) {        @SuppressWarnings("unchecked")        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,                new AsyncTaskResult
 
  (this, result));        message.sendToTarget();        return result;    }
 
SHandler is an InternalHandler with the following code:

 private static class InternalHandler extends Handler {        @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;            }        }    }
When a MESSAGE_POST_RESULT message is passed in, the AsyncTask. finish () method is executed. If this is a MESSAGE_POST_PROGRESS message, the onProgressUpdate () method is executed. When we use the for Loop in doInBackgroud (Params) to call publishProgress (Progress... values), we will simulate
Call onProgressUpdate (Progress... values) regularly. The source code of publishProgress (Progress... values) is as follows:

    protected final void publishProgress(Progress... values) {        if (!isCancelled()) {            sHandler.obtainMessage(MESSAGE_POST_PROGRESS,                    new AsyncTaskResult(this, values)).sendToTarget();        }    }
It first checks whether the thread has ended. If the thread has not ended, sHandler sends a message to himself. The message type is MESSAGE_POST_PROGRESS and sHandler. handleMessage (Message) will call onProgressUpdate (Progress... values ).
It can be seen from the above that sDefaultExecutor first calls mFuture's run (), while mFuture's run () will call mWorker's call (). After a task is executed, mFuture's done () is called back. Done () calls ppostResultIfNotInvoked (Result result). The source code is as follows:

    private void postResultIfNotInvoked(Result result) {        final boolean wasTaskInvoked = mTaskInvoked.get();        if (!wasTaskInvoked) {            postResult(result);        }    }
PostResult (Result) has been explained previously and will not be described here.






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.