AsyncTask.java revision 5e9120d4adfb07aeeadb0e0de1de2eb9ebbd80e0
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.os; 18 19import java.util.ArrayDeque; 20import java.util.concurrent.BlockingQueue; 21import java.util.concurrent.Callable; 22import java.util.concurrent.CancellationException; 23import java.util.concurrent.Executor; 24import java.util.concurrent.ExecutionException; 25import java.util.concurrent.FutureTask; 26import java.util.concurrent.LinkedBlockingQueue; 27import java.util.concurrent.ThreadFactory; 28import java.util.concurrent.ThreadPoolExecutor; 29import java.util.concurrent.TimeUnit; 30import java.util.concurrent.TimeoutException; 31import java.util.concurrent.atomic.AtomicBoolean; 32import java.util.concurrent.atomic.AtomicInteger; 33 34/** 35 * <p>AsyncTask enables proper and easy use of the UI thread. This class allows to 36 * perform background operations and publish results on the UI thread without 37 * having to manipulate threads and/or handlers.</p> 38 * 39 * <p>An asynchronous task is defined by a computation that runs on a background thread and 40 * whose result is published on the UI thread. An asynchronous task is defined by 3 generic 41 * types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>, 42 * and 4 steps, called <code>onPreExecute</code>, <code>doInBackground</code>, 43 * <code>onProgressUpdate</code> and <code>onPostExecute</code>.</p> 44 * 45 * <div class="special reference"> 46 * <h3>Developer Guides</h3> 47 * <p>For more information about using tasks and threads, read the 48 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html">Processes and 49 * Threads</a> developer guide.</p> 50 * </div> 51 * 52 * <h2>Usage</h2> 53 * <p>AsyncTask must be subclassed to be used. The subclass will override at least 54 * one method ({@link #doInBackground}), and most often will override a 55 * second one ({@link #onPostExecute}.)</p> 56 * 57 * <p>Here is an example of subclassing:</p> 58 * <pre class="prettyprint"> 59 * private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> { 60 * protected Long doInBackground(URL... urls) { 61 * int count = urls.length; 62 * long totalSize = 0; 63 * for (int i = 0; i < count; i++) { 64 * totalSize += Downloader.downloadFile(urls[i]); 65 * publishProgress((int) ((i / (float) count) * 100)); 66 * } 67 * return totalSize; 68 * } 69 * 70 * protected void onProgressUpdate(Integer... progress) { 71 * setProgressPercent(progress[0]); 72 * } 73 * 74 * protected void onPostExecute(Long result) { 75 * showDialog("Downloaded " + result + " bytes"); 76 * } 77 * } 78 * </pre> 79 * 80 * <p>Once created, a task is executed very simply:</p> 81 * <pre class="prettyprint"> 82 * new DownloadFilesTask().execute(url1, url2, url3); 83 * </pre> 84 * 85 * <h2>AsyncTask's generic types</h2> 86 * <p>The three types used by an asynchronous task are the following:</p> 87 * <ol> 88 * <li><code>Params</code>, the type of the parameters sent to the task upon 89 * execution.</li> 90 * <li><code>Progress</code>, the type of the progress units published during 91 * the background computation.</li> 92 * <li><code>Result</code>, the type of the result of the background 93 * computation.</li> 94 * </ol> 95 * <p>Not all types are always used by an asynchronous task. To mark a type as unused, 96 * simply use the type {@link Void}:</p> 97 * <pre> 98 * private class MyTask extends AsyncTask<Void, Void, Void> { ... } 99 * </pre> 100 * 101 * <h2>The 4 steps</h2> 102 * <p>When an asynchronous task is executed, the task goes through 4 steps:</p> 103 * <ol> 104 * <li>{@link #onPreExecute()}, invoked on the UI thread immediately after the task 105 * is executed. This step is normally used to setup the task, for instance by 106 * showing a progress bar in the user interface.</li> 107 * <li>{@link #doInBackground}, invoked on the background thread 108 * immediately after {@link #onPreExecute()} finishes executing. This step is used 109 * to perform background computation that can take a long time. The parameters 110 * of the asynchronous task are passed to this step. The result of the computation must 111 * be returned by this step and will be passed back to the last step. This step 112 * can also use {@link #publishProgress} to publish one or more units 113 * of progress. These values are published on the UI thread, in the 114 * {@link #onProgressUpdate} step.</li> 115 * <li>{@link #onProgressUpdate}, invoked on the UI thread after a 116 * call to {@link #publishProgress}. The timing of the execution is 117 * undefined. This method is used to display any form of progress in the user 118 * interface while the background computation is still executing. For instance, 119 * it can be used to animate a progress bar or show logs in a text field.</li> 120 * <li>{@link #onPostExecute}, invoked on the UI thread after the background 121 * computation finishes. The result of the background computation is passed to 122 * this step as a parameter.</li> 123 * </ol> 124 * 125 * <h2>Cancelling a task</h2> 126 * <p>A task can be cancelled at any time by invoking {@link #cancel(boolean)}. Invoking 127 * this method will cause subsequent calls to {@link #isCancelled()} to return true. 128 * After invoking this method, {@link #onCancelled(Object)}, instead of 129 * {@link #onPostExecute(Object)} will be invoked after {@link #doInBackground(Object[])} 130 * returns. To ensure that a task is cancelled as quickly as possible, you should always 131 * check the return value of {@link #isCancelled()} periodically from 132 * {@link #doInBackground(Object[])}, if possible (inside a loop for instance.)</p> 133 * 134 * <h2>Threading rules</h2> 135 * <p>There are a few threading rules that must be followed for this class to 136 * work properly:</p> 137 * <ul> 138 * <li>The AsyncTask class must be loaded on the UI thread. This is done 139 * automatically as of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}.</li> 140 * <li>The task instance must be created on the UI thread.</li> 141 * <li>{@link #execute} must be invoked on the UI thread.</li> 142 * <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute}, 143 * {@link #doInBackground}, {@link #onProgressUpdate} manually.</li> 144 * <li>The task can be executed only once (an exception will be thrown if 145 * a second execution is attempted.)</li> 146 * </ul> 147 * 148 * <h2>Memory observability</h2> 149 * <p>AsyncTask guarantees that all callback calls are synchronized in such a way that the following 150 * operations are safe without explicit synchronizations.</p> 151 * <ul> 152 * <li>Set member fields in the constructor or {@link #onPreExecute}, and refer to them 153 * in {@link #doInBackground}. 154 * <li>Set member fields in {@link #doInBackground}, and refer to them in 155 * {@link #onProgressUpdate} and {@link #onPostExecute}. 156 * </ul> 157 */ 158public abstract class AsyncTask<Params, Progress, Result> { 159 private static final String LOG_TAG = "AsyncTask"; 160 161 private static final int CORE_POOL_SIZE = 5; 162 private static final int MAXIMUM_POOL_SIZE = 128; 163 private static final int KEEP_ALIVE = 1; 164 165 private static final ThreadFactory sThreadFactory = new ThreadFactory() { 166 private final AtomicInteger mCount = new AtomicInteger(1); 167 168 public Thread newThread(Runnable r) { 169 return new Thread(r, "AsyncTask #" + mCount.getAndIncrement()); 170 } 171 }; 172 173 private static final BlockingQueue<Runnable> sPoolWorkQueue = 174 new LinkedBlockingQueue<Runnable>(10); 175 176 /** 177 * An {@link Executor} that can be used to execute tasks in parallel. 178 */ 179 public static final Executor THREAD_POOL_EXECUTOR 180 = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, 181 TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); 182 183 /** 184 * An {@link Executor} that executes tasks one at a time in serial 185 * order. This serialization is global to a particular process. 186 */ 187 public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); 188 189 private static final int MESSAGE_POST_RESULT = 0x1; 190 private static final int MESSAGE_POST_PROGRESS = 0x2; 191 192 private static final InternalHandler sHandler = new InternalHandler(); 193 194 private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; 195 private final WorkerRunnable<Params, Result> mWorker; 196 private final FutureTask<Result> mFuture; 197 198 private volatile Status mStatus = Status.PENDING; 199 200 private final AtomicBoolean mCancelled = new AtomicBoolean(); 201 private final AtomicBoolean mTaskInvoked = new AtomicBoolean(); 202 203 private static class SerialExecutor implements Executor { 204 final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); 205 Runnable mActive; 206 207 public synchronized void execute(final Runnable r) { 208 mTasks.offer(new Runnable() { 209 public void run() { 210 try { 211 r.run(); 212 } finally { 213 scheduleNext(); 214 } 215 } 216 }); 217 if (mActive == null) { 218 scheduleNext(); 219 } 220 } 221 222 protected synchronized void scheduleNext() { 223 if ((mActive = mTasks.poll()) != null) { 224 THREAD_POOL_EXECUTOR.execute(mActive); 225 } 226 } 227 } 228 229 /** 230 * Indicates the current status of the task. Each status will be set only once 231 * during the lifetime of a task. 232 */ 233 public enum Status { 234 /** 235 * Indicates that the task has not been executed yet. 236 */ 237 PENDING, 238 /** 239 * Indicates that the task is running. 240 */ 241 RUNNING, 242 /** 243 * Indicates that {@link AsyncTask#onPostExecute} has finished. 244 */ 245 FINISHED, 246 } 247 248 /** @hide Used to force static handler to be created. */ 249 public static void init() { 250 sHandler.getLooper(); 251 } 252 253 /** @hide */ 254 public static void setDefaultExecutor(Executor exec) { 255 sDefaultExecutor = exec; 256 } 257 258 /** 259 * Creates a new asynchronous task. This constructor must be invoked on the UI thread. 260 */ 261 public AsyncTask() { 262 mWorker = new WorkerRunnable<Params, Result>() { 263 public Result call() throws Exception { 264 mTaskInvoked.set(true); 265 266 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 267 //noinspection unchecked 268 return postResult(doInBackground(mParams)); 269 } 270 }; 271 272 mFuture = new FutureTask<Result>(mWorker) { 273 @Override 274 protected void done() { 275 try { 276 postResultIfNotInvoked(get()); 277 } catch (InterruptedException e) { 278 android.util.Log.w(LOG_TAG, e); 279 } catch (ExecutionException e) { 280 throw new RuntimeException("An error occured while executing doInBackground()", 281 e.getCause()); 282 } catch (CancellationException e) { 283 postResultIfNotInvoked(null); 284 } catch (Throwable t) { 285 throw new RuntimeException("An error occured while executing " 286 + "doInBackground()", t); 287 } 288 } 289 }; 290 } 291 292 private void postResultIfNotInvoked(Result result) { 293 final boolean wasTaskInvoked = mTaskInvoked.get(); 294 if (!wasTaskInvoked) { 295 postResult(result); 296 } 297 } 298 299 private Result postResult(Result result) { 300 @SuppressWarnings("unchecked") 301 Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, 302 new AsyncTaskResult<Result>(this, result)); 303 message.sendToTarget(); 304 return result; 305 } 306 307 /** 308 * Returns the current status of this task. 309 * 310 * @return The current status. 311 */ 312 public final Status getStatus() { 313 return mStatus; 314 } 315 316 /** 317 * Override this method to perform a computation on a background thread. The 318 * specified parameters are the parameters passed to {@link #execute} 319 * by the caller of this task. 320 * 321 * This method can call {@link #publishProgress} to publish updates 322 * on the UI thread. 323 * 324 * @param params The parameters of the task. 325 * 326 * @return A result, defined by the subclass of this task. 327 * 328 * @see #onPreExecute() 329 * @see #onPostExecute 330 * @see #publishProgress 331 */ 332 protected abstract Result doInBackground(Params... params); 333 334 /** 335 * Runs on the UI thread before {@link #doInBackground}. 336 * 337 * @see #onPostExecute 338 * @see #doInBackground 339 */ 340 protected void onPreExecute() { 341 } 342 343 /** 344 * <p>Runs on the UI thread after {@link #doInBackground}. The 345 * specified result is the value returned by {@link #doInBackground}.</p> 346 * 347 * <p>This method won't be invoked if the task was cancelled.</p> 348 * 349 * @param result The result of the operation computed by {@link #doInBackground}. 350 * 351 * @see #onPreExecute 352 * @see #doInBackground 353 * @see #onCancelled(Object) 354 */ 355 @SuppressWarnings({"UnusedDeclaration"}) 356 protected void onPostExecute(Result result) { 357 } 358 359 /** 360 * Runs on the UI thread after {@link #publishProgress} is invoked. 361 * The specified values are the values passed to {@link #publishProgress}. 362 * 363 * @param values The values indicating progress. 364 * 365 * @see #publishProgress 366 * @see #doInBackground 367 */ 368 @SuppressWarnings({"UnusedDeclaration"}) 369 protected void onProgressUpdate(Progress... values) { 370 } 371 372 /** 373 * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and 374 * {@link #doInBackground(Object[])} has finished.</p> 375 * 376 * <p>The default implementation simply invokes {@link #onCancelled()} and 377 * ignores the result. If you write your own implementation, do not call 378 * <code>super.onCancelled(result)</code>.</p> 379 * 380 * @param result The result, if any, computed in 381 * {@link #doInBackground(Object[])}, can be null 382 * 383 * @see #cancel(boolean) 384 * @see #isCancelled() 385 */ 386 @SuppressWarnings({"UnusedParameters"}) 387 protected void onCancelled(Result result) { 388 onCancelled(); 389 } 390 391 /** 392 * <p>Applications should preferably override {@link #onCancelled(Object)}. 393 * This method is invoked by the default implementation of 394 * {@link #onCancelled(Object)}.</p> 395 * 396 * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and 397 * {@link #doInBackground(Object[])} has finished.</p> 398 * 399 * @see #onCancelled(Object) 400 * @see #cancel(boolean) 401 * @see #isCancelled() 402 */ 403 protected void onCancelled() { 404 } 405 406 /** 407 * Returns <tt>true</tt> if this task was cancelled before it completed 408 * normally. If you are calling {@link #cancel(boolean)} on the task, 409 * the value returned by this method should be checked periodically from 410 * {@link #doInBackground(Object[])} to end the task as soon as possible. 411 * 412 * @return <tt>true</tt> if task was cancelled before it completed 413 * 414 * @see #cancel(boolean) 415 */ 416 public final boolean isCancelled() { 417 return mCancelled.get(); 418 } 419 420 /** 421 * <p>Attempts to cancel execution of this task. This attempt will 422 * fail if the task has already completed, already been cancelled, 423 * or could not be cancelled for some other reason. If successful, 424 * and this task has not started when <tt>cancel</tt> is called, 425 * this task should never run. If the task has already started, 426 * then the <tt>mayInterruptIfRunning</tt> parameter determines 427 * whether the thread executing this task should be interrupted in 428 * an attempt to stop the task.</p> 429 * 430 * <p>Calling this method will result in {@link #onCancelled(Object)} being 431 * invoked on the UI thread after {@link #doInBackground(Object[])} 432 * returns. Calling this method guarantees that {@link #onPostExecute(Object)} 433 * is never invoked. After invoking this method, you should check the 434 * value returned by {@link #isCancelled()} periodically from 435 * {@link #doInBackground(Object[])} to finish the task as early as 436 * possible.</p> 437 * 438 * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this 439 * task should be interrupted; otherwise, in-progress tasks are allowed 440 * to complete. 441 * 442 * @return <tt>false</tt> if the task could not be cancelled, 443 * typically because it has already completed normally; 444 * <tt>true</tt> otherwise 445 * 446 * @see #isCancelled() 447 * @see #onCancelled(Object) 448 */ 449 public final boolean cancel(boolean mayInterruptIfRunning) { 450 mCancelled.set(true); 451 return mFuture.cancel(mayInterruptIfRunning); 452 } 453 454 /** 455 * Waits if necessary for the computation to complete, and then 456 * retrieves its result. 457 * 458 * @return The computed result. 459 * 460 * @throws CancellationException If the computation was cancelled. 461 * @throws ExecutionException If the computation threw an exception. 462 * @throws InterruptedException If the current thread was interrupted 463 * while waiting. 464 */ 465 public final Result get() throws InterruptedException, ExecutionException { 466 return mFuture.get(); 467 } 468 469 /** 470 * Waits if necessary for at most the given time for the computation 471 * to complete, and then retrieves its result. 472 * 473 * @param timeout Time to wait before cancelling the operation. 474 * @param unit The time unit for the timeout. 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 interrupted 481 * while waiting. 482 * @throws TimeoutException If the wait timed out. 483 */ 484 public final Result get(long timeout, TimeUnit unit) throws InterruptedException, 485 ExecutionException, TimeoutException { 486 return mFuture.get(timeout, unit); 487 } 488 489 /** 490 * Executes the task with the specified parameters. The task returns 491 * itself (this) so that the caller can keep a reference to it. 492 * 493 * <p>Note: this function schedules the task on a queue for a single background 494 * thread or pool of threads depending on the platform version. When first 495 * introduced, AsyncTasks were executed serially on a single background thread. 496 * Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed 497 * to a pool of threads allowing multiple tasks to operate in parallel. After 498 * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, it is planned to change this 499 * back to a single thread to avoid common application errors caused 500 * by parallel execution. If you truly want parallel execution, you can use 501 * the {@link #executeOnExecutor} version of this method 502 * with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings on 503 * its use. 504 * 505 * <p>This method must be invoked on the UI thread. 506 * 507 * @param params The parameters of the task. 508 * 509 * @return This instance of AsyncTask. 510 * 511 * @throws IllegalStateException If {@link #getStatus()} returns either 512 * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}. 513 */ 514 public final AsyncTask<Params, Progress, Result> execute(Params... params) { 515 return executeOnExecutor(sDefaultExecutor, params); 516 } 517 518 /** 519 * Executes the task with the specified parameters. The task returns 520 * itself (this) so that the caller can keep a reference to it. 521 * 522 * <p>This method is typically used with {@link #THREAD_POOL_EXECUTOR} to 523 * allow multiple tasks to run in parallel on a pool of threads managed by 524 * AsyncTask, however you can also use your own {@link Executor} for custom 525 * behavior. 526 * 527 * <p><em>Warning:</em> Allowing multiple tasks to run in parallel from 528 * a thread pool is generally <em>not</em> what one wants, because the order 529 * of their operation is not defined. For example, if these tasks are used 530 * to modify any state in common (such as writing a file due to a button click), 531 * there are no guarantees on the order of the modifications. 532 * Without careful work it is possible in rare cases for the newer version 533 * of the data to be over-written by an older one, leading to obscure data 534 * loss and stability issues. Such changes are best 535 * executed in serial; to guarantee such work is serialized regardless of 536 * platform version you can use this function with {@link #SERIAL_EXECUTOR}. 537 * 538 * <p>This method must be invoked on the UI thread. 539 * 540 * @param exec The executor to use. {@link #THREAD_POOL_EXECUTOR} is available as a 541 * convenient process-wide thread pool for tasks that are loosely coupled. 542 * @param params The parameters of the task. 543 * 544 * @return This instance of AsyncTask. 545 * 546 * @throws IllegalStateException If {@link #getStatus()} returns either 547 * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}. 548 */ 549 public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, 550 Params... params) { 551 if (mStatus != Status.PENDING) { 552 switch (mStatus) { 553 case RUNNING: 554 throw new IllegalStateException("Cannot execute task:" 555 + " the task is already running."); 556 case FINISHED: 557 throw new IllegalStateException("Cannot execute task:" 558 + " the task has already been executed " 559 + "(a task can be executed only once)"); 560 } 561 } 562 563 mStatus = Status.RUNNING; 564 565 onPreExecute(); 566 567 mWorker.mParams = params; 568 exec.execute(mFuture); 569 570 return this; 571 } 572 573 /** 574 * Convenience version of {@link #execute(Object...)} for use with 575 * a simple Runnable object. 576 */ 577 public static void execute(Runnable runnable) { 578 sDefaultExecutor.execute(runnable); 579 } 580 581 /** 582 * This method can be invoked from {@link #doInBackground} to 583 * publish updates on the UI thread while the background computation is 584 * still running. Each call to this method will trigger the execution of 585 * {@link #onProgressUpdate} on the UI thread. 586 * 587 * {@link #onProgressUpdate} will note be called if the task has been 588 * canceled. 589 * 590 * @param values The progress values to update the UI with. 591 * 592 * @see #onProgressUpdate 593 * @see #doInBackground 594 */ 595 protected final void publishProgress(Progress... values) { 596 if (!isCancelled()) { 597 sHandler.obtainMessage(MESSAGE_POST_PROGRESS, 598 new AsyncTaskResult<Progress>(this, values)).sendToTarget(); 599 } 600 } 601 602 private void finish(Result result) { 603 if (isCancelled()) { 604 onCancelled(result); 605 } else { 606 onPostExecute(result); 607 } 608 mStatus = Status.FINISHED; 609 } 610 611 private static class InternalHandler extends Handler { 612 @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) 613 @Override 614 public void handleMessage(Message msg) { 615 AsyncTaskResult result = (AsyncTaskResult) msg.obj; 616 switch (msg.what) { 617 case MESSAGE_POST_RESULT: 618 // There is only one result 619 result.mTask.finish(result.mData[0]); 620 break; 621 case MESSAGE_POST_PROGRESS: 622 result.mTask.onProgressUpdate(result.mData); 623 break; 624 } 625 } 626 } 627 628 private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { 629 Params[] mParams; 630 } 631 632 @SuppressWarnings({"RawUseOfParameterizedType"}) 633 private static class AsyncTaskResult<Data> { 634 final AsyncTask mTask; 635 final Data[] mData; 636 637 AsyncTaskResult(AsyncTask task, Data... data) { 638 mTask = task; 639 mData = data; 640 } 641 } 642} 643