/*1* Copyright (C) 2008 The Android Open Source Project2*3* Licensed under the Apache License, Version 2.0 (the "License");4* you may not use this file except in compliance with the License.5* You may obtain a copy of the License at6*7* http://www.apache.org/licenses/LICENSE-2.08*9* Unless required by applicable law or agreed to in writing, software10* distributed under the License is distributed on an "AS IS" BASIS,11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12* See the License for the specific language governing permissions and13* limitations under the License.14*/1516package com.artifex.mupdfdemo;1718import java.util.concurrent.BlockingQueue;19import java.util.concurrent.Callable;20import java.util.concurrent.CancellationException;21import java.util.concurrent.ExecutionException;22import java.util.concurrent.Executor;23import java.util.concurrent.FutureTask;24import java.util.concurrent.LinkedBlockingQueue;25import java.util.concurrent.ThreadFactory;26import java.util.concurrent.ThreadPoolExecutor;27import java.util.concurrent.TimeUnit;28import java.util.concurrent.TimeoutException;29import java.util.concurrent.atomic.AtomicBoolean;30import java.util.concurrent.atomic.AtomicInteger;3132import android.os.Process;33import android.os.Handler;34import android.os.Message;3536/**37* <p>AsyncTask enables proper and easy use of the UI thread. This class allows to38* perform background operations and publish results on the UI thread without39* having to manipulate threads and/or handlers.</p>40*41* <p>AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}42* and does not constitute a generic threading framework. AsyncTasks should ideally be43* used for short operations (a few seconds at the most.) If you need to keep threads44* running for long periods of time, it is highly recommended you use the various APIs45* provided by the <code>java.util.concurrent</code> pacakge such as {@link Executor},46* {@link ThreadPoolExecutor} and {@link FutureTask}.</p>47*48* <p>An asynchronous task is defined by a computation that runs on a background thread and49* whose result is published on the UI thread. An asynchronous task is defined by 3 generic50* types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>,51* and 4 steps, called <code>onPreExecute</code>, <code>doInBackground</code>,52* <code>onProgressUpdate</code> and <code>onPostExecute</code>.</p>53*54* <div class="special reference">55* <h3>Developer Guides</h3>56* <p>For more information about using tasks and threads, read the57* <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html">Processes and58* Threads</a> developer guide.</p>59* </div>60*61* <h2>Usage</h2>62* <p>AsyncTask must be subclassed to be used. The subclass will override at least63* one method ({@link #doInBackground}), and most often will override a64* second one ({@link #onPostExecute}.)</p>65*66* <p>Here is an example of subclassing:</p>67* <pre class="prettyprint">68* private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {69* protected Long doInBackground(URL... urls) {70* int count = urls.length;71* long totalSize = 0;72* for (int i = 0; i < count; i++) {73* totalSize += Downloader.downloadFile(urls[i]);74* publishProgress((int) ((i / (float) count) * 100));75* // Escape early if cancel() is called76* if (isCancelled()) break;77* }78* return totalSize;79* }80*81* protected void onProgressUpdate(Integer... progress) {82* setProgressPercent(progress[0]);83* }84*85* protected void onPostExecute(Long result) {86* showDialog("Downloaded " + result + " bytes");87* }88* }89* </pre>90*91* <p>Once created, a task is executed very simply:</p>92* <pre class="prettyprint">93* new DownloadFilesTask().execute(url1, url2, url3);94* </pre>95*96* <h2>AsyncTask's generic types</h2>97* <p>The three types used by an asynchronous task are the following:</p>98* <ol>99* <li><code>Params</code>, the type of the parameters sent to the task upon100* execution.</li>101* <li><code>Progress</code>, the type of the progress units published during102* the background computation.</li>103* <li><code>Result</code>, the type of the result of the background104* computation.</li>105* </ol>106* <p>Not all types are always used by an asynchronous task. To mark a type as unused,107* simply use the type {@link Void}:</p>108* <pre>109* private class MyTask extends AsyncTask<Void, Void, Void> { ... }110* </pre>111*112* <h2>The 4 steps</h2>113* <p>When an asynchronous task is executed, the task goes through 4 steps:</p>114* <ol>115* <li>{@link #onPreExecute()}, invoked on the UI thread before the task116* is executed. This step is normally used to setup the task, for instance by117* showing a progress bar in the user interface.</li>118* <li>{@link #doInBackground}, invoked on the background thread119* immediately after {@link #onPreExecute()} finishes executing. This step is used120* to perform background computation that can take a long time. The parameters121* of the asynchronous task are passed to this step. The result of the computation must122* be returned by this step and will be passed back to the last step. This step123* can also use {@link #publishProgress} to publish one or more units124* of progress. These values are published on the UI thread, in the125* {@link #onProgressUpdate} step.</li>126* <li>{@link #onProgressUpdate}, invoked on the UI thread after a127* call to {@link #publishProgress}. The timing of the execution is128* undefined. This method is used to display any form of progress in the user129* interface while the background computation is still executing. For instance,130* it can be used to animate a progress bar or show logs in a text field.</li>131* <li>{@link #onPostExecute}, invoked on the UI thread after the background132* computation finishes. The result of the background computation is passed to133* this step as a parameter.</li>134* </ol>135*136* <h2>Cancelling a task</h2>137* <p>A task can be cancelled at any time by invoking {@link #cancel(boolean)}. Invoking138* this method will cause subsequent calls to {@link #isCancelled()} to return true.139* After invoking this method, {@link #onCancelled(Object)}, instead of140* {@link #onPostExecute(Object)} will be invoked after {@link #doInBackground(Object[])}141* returns. To ensure that a task is cancelled as quickly as possible, you should always142* check the return value of {@link #isCancelled()} periodically from143* {@link #doInBackground(Object[])}, if possible (inside a loop for instance.)</p>144*145* <h2>Threading rules</h2>146* <p>There are a few threading rules that must be followed for this class to147* work properly:</p>148* <ul>149* <li>The AsyncTask class must be loaded on the UI thread. This is done150* automatically as of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}.</li>151* <li>The task instance must be created on the UI thread.</li>152* <li>{@link #execute} must be invoked on the UI thread.</li>153* <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute},154* {@link #doInBackground}, {@link #onProgressUpdate} manually.</li>155* <li>The task can be executed only once (an exception will be thrown if156* a second execution is attempted.)</li>157* </ul>158*159* <h2>Memory observability</h2>160* <p>AsyncTask guarantees that all callback calls are synchronized in such a way that the following161* operations are safe without explicit synchronizations.</p>162* <ul>163* <li>Set member fields in the constructor or {@link #onPreExecute}, and refer to them164* in {@link #doInBackground}.165* <li>Set member fields in {@link #doInBackground}, and refer to them in166* {@link #onProgressUpdate} and {@link #onPostExecute}.167* </ul>168*169* <h2>Order of execution</h2>170* <p>When first introduced, AsyncTasks were executed serially on a single background171* thread. Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed172* to a pool of threads allowing multiple tasks to operate in parallel. Starting with173* {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are executed on a single174* thread to avoid common application errors caused by parallel execution.</p>175* <p>If you truly want parallel execution, you can invoke176* {@link #executeOnExecutor(java.util.concurrent.Executor, Object[])} with177* {@link #THREAD_POOL_EXECUTOR}.</p>178*/179public abstract class AsyncTask<Params, Progress, Result> {180private static final String LOG_TAG = "AsyncTask";181182private static final int CORE_POOL_SIZE = 5;183private static final int MAXIMUM_POOL_SIZE = 128;184private static final int KEEP_ALIVE = 1;185186private static final ThreadFactory sThreadFactory = new ThreadFactory() {187private final AtomicInteger mCount = new AtomicInteger(1);188189public Thread newThread(Runnable r) {190return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());191}192};193194private static final BlockingQueue<Runnable> sPoolWorkQueue =195new LinkedBlockingQueue<Runnable>(10);196197/**198* An {@link Executor} that can be used to execute tasks in parallel.199*/200public static final Executor THREAD_POOL_EXECUTOR201= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,202TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);203204/**205* An {@link Executor} that executes tasks one at a time in serial206* order. This serialization is global to a particular process.207*/208public static final Executor SERIAL_EXECUTOR = new SerialExecutor();209210private static final int MESSAGE_POST_RESULT = 0x1;211private static final int MESSAGE_POST_PROGRESS = 0x2;212213private static final InternalHandler sHandler = new InternalHandler();214215private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;216private final WorkerRunnable<Params, Result> mWorker;217private final FutureTask<Result> mFuture;218219private volatile Status mStatus = Status.PENDING;220221private final AtomicBoolean mCancelled = new AtomicBoolean();222private final AtomicBoolean mTaskInvoked = new AtomicBoolean();223224private static class SerialExecutor implements Executor {225final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();226Runnable mActive;227228public synchronized void execute(final Runnable r) {229mTasks.offer(new Runnable() {230public void run() {231try {232r.run();233} finally {234scheduleNext();235}236}237});238if (mActive == null) {239scheduleNext();240}241}242243protected synchronized void scheduleNext() {244if ((mActive = mTasks.poll()) != null) {245THREAD_POOL_EXECUTOR.execute(mActive);246}247}248}249250/**251* Indicates the current status of the task. Each status will be set only once252* during the lifetime of a task.253*/254public enum Status {255/**256* Indicates that the task has not been executed yet.257*/258PENDING,259/**260* Indicates that the task is running.261*/262RUNNING,263/**264* Indicates that {@link AsyncTask#onPostExecute} has finished.265*/266FINISHED,267}268269/** @hide Used to force static handler to be created. */270public static void init() {271sHandler.getLooper();272}273274/** @hide */275public static void setDefaultExecutor(Executor exec) {276sDefaultExecutor = exec;277}278279/**280* Creates a new asynchronous task. This constructor must be invoked on the UI thread.281*/282public AsyncTask() {283mWorker = new WorkerRunnable<Params, Result>() {284public Result call() throws Exception {285mTaskInvoked.set(true);286287Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);288//noinspection unchecked289return postResult(doInBackground(mParams));290}291};292293mFuture = new FutureTask<Result>(mWorker) {294@Override295protected void done() {296try {297postResultIfNotInvoked(get());298} catch (InterruptedException e) {299android.util.Log.w(LOG_TAG, e);300} catch (ExecutionException e) {301throw new RuntimeException("An error occured while executing doInBackground()",302e.getCause());303} catch (CancellationException e) {304postResultIfNotInvoked(null);305}306}307};308}309310private void postResultIfNotInvoked(Result result) {311final boolean wasTaskInvoked = mTaskInvoked.get();312if (!wasTaskInvoked) {313postResult(result);314}315}316317private Result postResult(Result result) {318@SuppressWarnings("unchecked")319Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,320new AsyncTaskResult<Result>(this, result));321message.sendToTarget();322return result;323}324325/**326* Returns the current status of this task.327*328* @return The current status.329*/330public final Status getStatus() {331return mStatus;332}333334/**335* Override this method to perform a computation on a background thread. The336* specified parameters are the parameters passed to {@link #execute}337* by the caller of this task.338*339* This method can call {@link #publishProgress} to publish updates340* on the UI thread.341*342* @param params The parameters of the task.343*344* @return A result, defined by the subclass of this task.345*346* @see #onPreExecute()347* @see #onPostExecute348* @see #publishProgress349*/350protected abstract Result doInBackground(Params... params);351352/**353* Runs on the UI thread before {@link #doInBackground}.354*355* @see #onPostExecute356* @see #doInBackground357*/358protected void onPreExecute() {359}360361/**362* <p>Runs on the UI thread after {@link #doInBackground}. The363* specified result is the value returned by {@link #doInBackground}.</p>364*365* <p>This method won't be invoked if the task was cancelled.</p>366*367* @param result The result of the operation computed by {@link #doInBackground}.368*369* @see #onPreExecute370* @see #doInBackground371* @see #onCancelled(Object)372*/373@SuppressWarnings({"UnusedDeclaration"})374protected void onPostExecute(Result result) {375}376377/**378* Runs on the UI thread after {@link #publishProgress} is invoked.379* The specified values are the values passed to {@link #publishProgress}.380*381* @param values The values indicating progress.382*383* @see #publishProgress384* @see #doInBackground385*/386@SuppressWarnings({"UnusedDeclaration"})387protected void onProgressUpdate(Progress... values) {388}389390/**391* <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and392* {@link #doInBackground(Object[])} has finished.</p>393*394* <p>The default implementation simply invokes {@link #onCancelled()} and395* ignores the result. If you write your own implementation, do not call396* <code>super.onCancelled(result)</code>.</p>397*398* @param result The result, if any, computed in399* {@link #doInBackground(Object[])}, can be null400*401* @see #cancel(boolean)402* @see #isCancelled()403*/404@SuppressWarnings({"UnusedParameters"})405protected void onCancelled(Result result) {406onCancelled();407}408409/**410* <p>Applications should preferably override {@link #onCancelled(Object)}.411* This method is invoked by the default implementation of412* {@link #onCancelled(Object)}.</p>413*414* <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and415* {@link #doInBackground(Object[])} has finished.</p>416*417* @see #onCancelled(Object)418* @see #cancel(boolean)419* @see #isCancelled()420*/421protected void onCancelled() {422}423424/**425* Returns <tt>true</tt> if this task was cancelled before it completed426* normally. If you are calling {@link #cancel(boolean)} on the task,427* the value returned by this method should be checked periodically from428* {@link #doInBackground(Object[])} to end the task as soon as possible.429*430* @return <tt>true</tt> if task was cancelled before it completed431*432* @see #cancel(boolean)433*/434public final boolean isCancelled() {435return mCancelled.get();436}437438/**439* <p>Attempts to cancel execution of this task. This attempt will440* fail if the task has already completed, already been cancelled,441* or could not be cancelled for some other reason. If successful,442* and this task has not started when <tt>cancel</tt> is called,443* this task should never run. If the task has already started,444* then the <tt>mayInterruptIfRunning</tt> parameter determines445* whether the thread executing this task should be interrupted in446* an attempt to stop the task.</p>447*448* <p>Calling this method will result in {@link #onCancelled(Object)} being449* invoked on the UI thread after {@link #doInBackground(Object[])}450* returns. Calling this method guarantees that {@link #onPostExecute(Object)}451* is never invoked. After invoking this method, you should check the452* value returned by {@link #isCancelled()} periodically from453* {@link #doInBackground(Object[])} to finish the task as early as454* possible.</p>455*456* @param mayInterruptIfRunning <tt>true</tt> if the thread executing this457* task should be interrupted; otherwise, in-progress tasks are allowed458* to complete.459*460* @return <tt>false</tt> if the task could not be cancelled,461* typically because it has already completed normally;462* <tt>true</tt> otherwise463*464* @see #isCancelled()465* @see #onCancelled(Object)466*/467public final boolean cancel(boolean mayInterruptIfRunning) {468mCancelled.set(true);469return mFuture.cancel(mayInterruptIfRunning);470}471472/**473* Waits if necessary for the computation to complete, and then474* retrieves its result.475*476* @return The computed result.477*478* @throws CancellationException If the computation was cancelled.479* @throws ExecutionException If the computation threw an exception.480* @throws InterruptedException If the current thread was interrupted481* while waiting.482*/483public final Result get() throws InterruptedException, ExecutionException {484return mFuture.get();485}486487/**488* Waits if necessary for at most the given time for the computation489* to complete, and then retrieves its result.490*491* @param timeout Time to wait before cancelling the operation.492* @param unit The time unit for the timeout.493*494* @return The computed result.495*496* @throws CancellationException If the computation was cancelled.497* @throws ExecutionException If the computation threw an exception.498* @throws InterruptedException If the current thread was interrupted499* while waiting.500* @throws TimeoutException If the wait timed out.501*/502public final Result get(long timeout, TimeUnit unit) throws InterruptedException,503ExecutionException, TimeoutException {504return mFuture.get(timeout, unit);505}506507/**508* Executes the task with the specified parameters. The task returns509* itself (this) so that the caller can keep a reference to it.510*511* <p>Note: this function schedules the task on a queue for a single background512* thread or pool of threads depending on the platform version. When first513* introduced, AsyncTasks were executed serially on a single background thread.514* Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed515* to a pool of threads allowing multiple tasks to operate in parallel. Starting516* {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being517* executed on a single thread to avoid common application errors caused518* by parallel execution. If you truly want parallel execution, you can use519* the {@link #executeOnExecutor} version of this method520* with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings521* on its use.522*523* <p>This method must be invoked on the UI thread.524*525* @param params The parameters of the task.526*527* @return This instance of AsyncTask.528*529* @throws IllegalStateException If {@link #getStatus()} returns either530* {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.531*532* @see #executeOnExecutor(java.util.concurrent.Executor, Object[])533* @see #execute(Runnable)534*/535public final AsyncTask<Params, Progress, Result> execute(Params... params) {536return executeOnExecutor(sDefaultExecutor, params);537}538539/**540* Executes the task with the specified parameters. The task returns541* itself (this) so that the caller can keep a reference to it.542*543* <p>This method is typically used with {@link #THREAD_POOL_EXECUTOR} to544* allow multiple tasks to run in parallel on a pool of threads managed by545* AsyncTask, however you can also use your own {@link Executor} for custom546* behavior.547*548* <p><em>Warning:</em> Allowing multiple tasks to run in parallel from549* a thread pool is generally <em>not</em> what one wants, because the order550* of their operation is not defined. For example, if these tasks are used551* to modify any state in common (such as writing a file due to a button click),552* there are no guarantees on the order of the modifications.553* Without careful work it is possible in rare cases for the newer version554* of the data to be over-written by an older one, leading to obscure data555* loss and stability issues. Such changes are best556* executed in serial; to guarantee such work is serialized regardless of557* platform version you can use this function with {@link #SERIAL_EXECUTOR}.558*559* <p>This method must be invoked on the UI thread.560*561* @param exec The executor to use. {@link #THREAD_POOL_EXECUTOR} is available as a562* convenient process-wide thread pool for tasks that are loosely coupled.563* @param params The parameters of the task.564*565* @return This instance of AsyncTask.566*567* @throws IllegalStateException If {@link #getStatus()} returns either568* {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.569*570* @see #execute(Object[])571*/572public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,573Params... params) {574if (mStatus != Status.PENDING) {575switch (mStatus) {576case RUNNING:577throw new IllegalStateException("Cannot execute task:"578+ " the task is already running.");579case FINISHED:580throw new IllegalStateException("Cannot execute task:"581+ " the task has already been executed "582+ "(a task can be executed only once)");583}584}585586mStatus = Status.RUNNING;587588onPreExecute();589590mWorker.mParams = params;591exec.execute(mFuture);592593return this;594}595596/**597* Convenience version of {@link #execute(Object...)} for use with598* a simple Runnable object. See {@link #execute(Object[])} for more599* information on the order of execution.600*601* @see #execute(Object[])602* @see #executeOnExecutor(java.util.concurrent.Executor, Object[])603*/604public static void execute(Runnable runnable) {605sDefaultExecutor.execute(runnable);606}607608/**609* This method can be invoked from {@link #doInBackground} to610* publish updates on the UI thread while the background computation is611* still running. Each call to this method will trigger the execution of612* {@link #onProgressUpdate} on the UI thread.613*614* {@link #onProgressUpdate} will note be called if the task has been615* canceled.616*617* @param values The progress values to update the UI with.618*619* @see #onProgressUpdate620* @see #doInBackground621*/622protected final void publishProgress(Progress... values) {623if (!isCancelled()) {624sHandler.obtainMessage(MESSAGE_POST_PROGRESS,625new AsyncTaskResult<Progress>(this, values)).sendToTarget();626}627}628629private void finish(Result result) {630if (isCancelled()) {631onCancelled(result);632} else {633onPostExecute(result);634}635mStatus = Status.FINISHED;636}637638private static class InternalHandler extends Handler {639@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})640@Override641public void handleMessage(Message msg) {642AsyncTaskResult result = (AsyncTaskResult) msg.obj;643switch (msg.what) {644case MESSAGE_POST_RESULT:645// There is only one result646result.mTask.finish(result.mData[0]);647break;648case MESSAGE_POST_PROGRESS:649result.mTask.onProgressUpdate(result.mData);650break;651}652}653}654655private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {656Params[] mParams;657}658659@SuppressWarnings({"RawUseOfParameterizedType"})660private static class AsyncTaskResult<Data> {661final AsyncTask mTask;662final Data[] mData;663664AsyncTaskResult(AsyncTask task, Data... data) {665mTask = task;666mData = data;667}668}669}670671672