AsyncTask.java revision 81de61bfddceba0eb77b3aacea317594b0f1de49
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 * <h2>Usage</h2> 46 * <p>AsyncTask must be subclassed to be used. The subclass will override at least 47 * one method ({@link #doInBackground}), and most often will override a 48 * second one ({@link #onPostExecute}.)</p> 49 * 50 * <p>Here is an example of subclassing:</p> 51 * <pre class="prettyprint"> 52 * private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> { 53 * protected Long doInBackground(URL... urls) { 54 * int count = urls.length; 55 * long totalSize = 0; 56 * for (int i = 0; i < count; i++) { 57 * totalSize += Downloader.downloadFile(urls[i]); 58 * publishProgress((int) ((i / (float) count) * 100)); 59 * } 60 * return totalSize; 61 * } 62 * 63 * protected void onProgressUpdate(Integer... progress) { 64 * setProgressPercent(progress[0]); 65 * } 66 * 67 * protected void onPostExecute(Long result) { 68 * showDialog("Downloaded " + result + " bytes"); 69 * } 70 * } 71 * </pre> 72 * 73 * <p>Once created, a task is executed very simply:</p> 74 * <pre class="prettyprint"> 75 * new DownloadFilesTask().execute(url1, url2, url3); 76 * </pre> 77 * 78 * <h2>AsyncTask's generic types</h2> 79 * <p>The three types used by an asynchronous task are the following:</p> 80 * <ol> 81 * <li><code>Params</code>, the type of the parameters sent to the task upon 82 * execution.</li> 83 * <li><code>Progress</code>, the type of the progress units published during 84 * the background computation.</li> 85 * <li><code>Result</code>, the type of the result of the background 86 * computation.</li> 87 * </ol> 88 * <p>Not all types are always used by an asynchronous task. To mark a type as unused, 89 * simply use the type {@link Void}:</p> 90 * <pre> 91 * private class MyTask extends AsyncTask<Void, Void, Void> { ... } 92 * </pre> 93 * 94 * <h2>The 4 steps</h2> 95 * <p>When an asynchronous task is executed, the task goes through 4 steps:</p> 96 * <ol> 97 * <li>{@link #onPreExecute()}, invoked on the UI thread immediately after the task 98 * is executed. This step is normally used to setup the task, for instance by 99 * showing a progress bar in the user interface.</li> 100 * <li>{@link #doInBackground}, invoked on the background thread 101 * immediately after {@link #onPreExecute()} finishes executing. This step is used 102 * to perform background computation that can take a long time. The parameters 103 * of the asynchronous task are passed to this step. The result of the computation must 104 * be returned by this step and will be passed back to the last step. This step 105 * can also use {@link #publishProgress} to publish one or more units 106 * of progress. These values are published on the UI thread, in the 107 * {@link #onProgressUpdate} step.</li> 108 * <li>{@link #onProgressUpdate}, invoked on the UI thread after a 109 * call to {@link #publishProgress}. The timing of the execution is 110 * undefined. This method is used to display any form of progress in the user 111 * interface while the background computation is still executing. For instance, 112 * it can be used to animate a progress bar or show logs in a text field.</li> 113 * <li>{@link #onPostExecute}, invoked on the UI thread after the background 114 * computation finishes. The result of the background computation is passed to 115 * this step as a parameter.</li> 116 * </ol> 117 * 118 * <h2>Cancelling a task</h2> 119 * <p>A task can be cancelled at any time by invoking {@link #cancel(boolean)}. Invoking 120 * this method will cause subsequent calls to {@link #isCancelled()} to return true. 121 * After invoking this method, {@link #onCancelled(Object)}, instead of 122 * {@link #onPostExecute(Object)} will be invoked after {@link #doInBackground(Object[])} 123 * returns. To ensure that a task is cancelled as quickly as possible, you should always 124 * check the return value of {@link #isCancelled()} periodically from 125 * {@link #doInBackground(Object[])}, if possible (inside a loop for instance.)</p> 126 * 127 * <h2>Threading rules</h2> 128 * <p>There are a few threading rules that must be followed for this class to 129 * work properly:</p> 130 * <ul> 131 * <li>The task instance must be created on the UI thread.</li> 132 * <li>{@link #execute} must be invoked on the UI thread.</li> 133 * <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute}, 134 * {@link #doInBackground}, {@link #onProgressUpdate} manually.</li> 135 * <li>The task can be executed only once (an exception will be thrown if 136 * a second execution is attempted.)</li> 137 * </ul> 138 * 139 * <h2>Memory observability</h2> 140 * <p>AsyncTask guarantees that all callback calls are synchronized in such a way that the following 141 * operations are safe without explicit synchronizations.</p> 142 * <ul> 143 * <li>Set member fields in the constructor or {@link #onPreExecute}, and refer to them 144 * in {@link #doInBackground}. 145 * <li>Set member fields in {@link #doInBackground}, and refer to them in 146 * {@link #onProgressUpdate} and {@link #onPostExecute}. 147 * </ul> 148 */ 149public abstract class AsyncTask<Params, Progress, Result> { 150 private static final String LOG_TAG = "AsyncTask"; 151 152 private static final int CORE_POOL_SIZE = 5; 153 private static final int MAXIMUM_POOL_SIZE = 128; 154 private static final int KEEP_ALIVE = 1; 155 156 157 private static final ThreadFactory sThreadFactory = new ThreadFactory() { 158 private final AtomicInteger mCount = new AtomicInteger(1); 159 160 public Thread newThread(Runnable r) { 161 return new Thread(r, "AsyncTask #" + mCount.getAndIncrement()); 162 } 163 }; 164 165 private static final BlockingQueue<Runnable> sPoolWorkQueue = 166 new LinkedBlockingQueue<Runnable>(10); 167 168 /** 169 * A {@link ThreadPoolExecutor} that can be used to execute tasks in parallel. 170 */ 171 public static final ThreadPoolExecutor THREAD_POOL_EXECUTOR 172 = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, 173 TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); 174 175 private static final SerialExecutor sSerialExecutor = new SerialExecutor(); 176 177 private static final int MESSAGE_POST_RESULT = 0x1; 178 private static final int MESSAGE_POST_PROGRESS = 0x2; 179 180 private static final InternalHandler sHandler = new InternalHandler(); 181 182 private final WorkerRunnable<Params, Result> mWorker; 183 private final FutureTask<Result> mFuture; 184 185 private volatile Status mStatus = Status.PENDING; 186 187 private final AtomicBoolean mTaskInvoked = new AtomicBoolean(); 188 189 private static class SerialExecutor implements Executor { 190 final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); 191 Runnable mActive; 192 193 public synchronized void execute(final Runnable r) { 194 mTasks.offer(new Runnable() { 195 public void run() { 196 try { 197 r.run(); 198 } finally { 199 scheduleNext(); 200 } 201 } 202 }); 203 if (mActive == null) { 204 scheduleNext(); 205 } 206 } 207 208 protected synchronized void scheduleNext() { 209 if ((mActive = mTasks.poll()) != null) { 210 THREAD_POOL_EXECUTOR.execute(mActive); 211 } 212 } 213 } 214 215 /** 216 * Indicates the current status of the task. Each status will be set only once 217 * during the lifetime of a task. 218 */ 219 public enum Status { 220 /** 221 * Indicates that the task has not been executed yet. 222 */ 223 PENDING, 224 /** 225 * Indicates that the task is running. 226 */ 227 RUNNING, 228 /** 229 * Indicates that {@link AsyncTask#onPostExecute} has finished. 230 */ 231 FINISHED, 232 } 233 234 /** @hide Used to force static handler to be created. */ 235 public static void init() { 236 sHandler.getLooper(); 237 } 238 239 /** 240 * Creates a new asynchronous task. This constructor must be invoked on the UI thread. 241 */ 242 public AsyncTask() { 243 mWorker = new WorkerRunnable<Params, Result>() { 244 public Result call() throws Exception { 245 mTaskInvoked.set(true); 246 247 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 248 return postResult(doInBackground(mParams)); 249 } 250 }; 251 252 mFuture = new FutureTask<Result>(mWorker) { 253 @Override 254 protected void done() { 255 try { 256 final Result result = get(); 257 258 postResultIfNotInvoked(result); 259 } catch (InterruptedException e) { 260 android.util.Log.w(LOG_TAG, e); 261 } catch (ExecutionException e) { 262 throw new RuntimeException("An error occured while executing doInBackground()", 263 e.getCause()); 264 } catch (CancellationException e) { 265 postResultIfNotInvoked(null); 266 } catch (Throwable t) { 267 throw new RuntimeException("An error occured while executing " 268 + "doInBackground()", t); 269 } 270 } 271 }; 272 } 273 274 private void postResultIfNotInvoked(Result result) { 275 final boolean wasTaskInvoked = mTaskInvoked.get(); 276 if (!wasTaskInvoked) { 277 postResult(result); 278 } 279 } 280 281 private Result postResult(Result result) { 282 Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, 283 new AsyncTaskResult<Result>(this, result)); 284 message.sendToTarget(); 285 return result; 286 } 287 288 /** 289 * Returns the current status of this task. 290 * 291 * @return The current status. 292 */ 293 public final Status getStatus() { 294 return mStatus; 295 } 296 297 /** 298 * Override this method to perform a computation on a background thread. The 299 * specified parameters are the parameters passed to {@link #execute} 300 * by the caller of this task. 301 * 302 * This method can call {@link #publishProgress} to publish updates 303 * on the UI thread. 304 * 305 * @param params The parameters of the task. 306 * 307 * @return A result, defined by the subclass of this task. 308 * 309 * @see #onPreExecute() 310 * @see #onPostExecute 311 * @see #publishProgress 312 */ 313 protected abstract Result doInBackground(Params... params); 314 315 /** 316 * Runs on the UI thread before {@link #doInBackground}. 317 * 318 * @see #onPostExecute 319 * @see #doInBackground 320 */ 321 protected void onPreExecute() { 322 } 323 324 /** 325 * <p>Runs on the UI thread after {@link #doInBackground}. The 326 * specified result is the value returned by {@link #doInBackground}.</p> 327 * 328 * <p>This method won't be invoked if the task was cancelled.</p> 329 * 330 * @param result The result of the operation computed by {@link #doInBackground}. 331 * 332 * @see #onPreExecute 333 * @see #doInBackground 334 * @see #onCancelled(Object) 335 */ 336 @SuppressWarnings({"UnusedDeclaration"}) 337 protected void onPostExecute(Result result) { 338 } 339 340 /** 341 * Runs on the UI thread after {@link #publishProgress} is invoked. 342 * The specified values are the values passed to {@link #publishProgress}. 343 * 344 * @param values The values indicating progress. 345 * 346 * @see #publishProgress 347 * @see #doInBackground 348 */ 349 @SuppressWarnings({"UnusedDeclaration"}) 350 protected void onProgressUpdate(Progress... values) { 351 } 352 353 /** 354 * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and 355 * {@link #doInBackground(Object[])} has finished.</p> 356 * 357 * <p>The default implementation simply invokes {@link #onCancelled()} and 358 * ignores the result. If you write your own implementation, do not call 359 * <code>super.onCancelled(result)</code>.</p> 360 * 361 * @param result The result, if any, computed in 362 * {@link #doInBackground(Object[])}, can be null 363 * 364 * @see #cancel(boolean) 365 * @see #isCancelled() 366 */ 367 @SuppressWarnings({"UnusedParameters"}) 368 protected void onCancelled(Result result) { 369 onCancelled(); 370 } 371 372 /** 373 * <p>Applications should preferably override {@link #onCancelled(Object)}. 374 * This method is invoked by the default implementation of 375 * {@link #onCancelled(Object)}.</p> 376 * 377 * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and 378 * {@link #doInBackground(Object[])} has finished.</p> 379 * 380 * @see #onCancelled(Object) 381 * @see #cancel(boolean) 382 * @see #isCancelled() 383 */ 384 protected void onCancelled() { 385 } 386 387 /** 388 * Returns <tt>true</tt> if this task was cancelled before it completed 389 * normally. If you are calling {@link #cancel(boolean)} on the task, 390 * the value returned by this method should be checked periodically from 391 * {@link #doInBackground(Object[])} to end the task as soon as possible. 392 * 393 * @return <tt>true</tt> if task was cancelled before it completed 394 * 395 * @see #cancel(boolean) 396 */ 397 public final boolean isCancelled() { 398 return mFuture.isCancelled(); 399 } 400 401 /** 402 * <p>Attempts to cancel execution of this task. This attempt will 403 * fail if the task has already completed, already been cancelled, 404 * or could not be cancelled for some other reason. If successful, 405 * and this task has not started when <tt>cancel</tt> is called, 406 * this task should never run. If the task has already started, 407 * then the <tt>mayInterruptIfRunning</tt> parameter determines 408 * whether the thread executing this task should be interrupted in 409 * an attempt to stop the task.</p> 410 * 411 * <p>Calling this method will result in {@link #onCancelled(Object)} being 412 * invoked on the UI thread after {@link #doInBackground(Object[])} 413 * returns. Calling this method guarantees that {@link #onPostExecute(Object)} 414 * is never invoked. After invoking this method, you should check the 415 * value returned by {@link #isCancelled()} periodically from 416 * {@link #doInBackground(Object[])} to finish the task as early as 417 * possible.</p> 418 * 419 * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this 420 * task should be interrupted; otherwise, in-progress tasks are allowed 421 * to complete. 422 * 423 * @return <tt>false</tt> if the task could not be cancelled, 424 * typically because it has already completed normally; 425 * <tt>true</tt> otherwise 426 * 427 * @see #isCancelled() 428 * @see #onCancelled(Object) 429 */ 430 public final boolean cancel(boolean mayInterruptIfRunning) { 431 return mFuture.cancel(mayInterruptIfRunning); 432 } 433 434 /** 435 * Waits if necessary for the computation to complete, and then 436 * retrieves its result. 437 * 438 * @return The computed result. 439 * 440 * @throws CancellationException If the computation was cancelled. 441 * @throws ExecutionException If the computation threw an exception. 442 * @throws InterruptedException If the current thread was interrupted 443 * while waiting. 444 */ 445 public final Result get() throws InterruptedException, ExecutionException { 446 return mFuture.get(); 447 } 448 449 /** 450 * Waits if necessary for at most the given time for the computation 451 * to complete, and then retrieves its result. 452 * 453 * @param timeout Time to wait before cancelling the operation. 454 * @param unit The time unit for the timeout. 455 * 456 * @return The computed result. 457 * 458 * @throws CancellationException If the computation was cancelled. 459 * @throws ExecutionException If the computation threw an exception. 460 * @throws InterruptedException If the current thread was interrupted 461 * while waiting. 462 * @throws TimeoutException If the wait timed out. 463 */ 464 public final Result get(long timeout, TimeUnit unit) throws InterruptedException, 465 ExecutionException, TimeoutException { 466 return mFuture.get(timeout, unit); 467 } 468 469 /** 470 * Executes the task with the specified parameters. The task returns 471 * itself (this) so that the caller can keep a reference to it. The tasks 472 * started by all invocations of this method in a given process are run 473 * sequentially. Call the {@link #execute(Executor,Params...) execute(Executor,Params...)} 474 * with a custom {@link Executor} to have finer grained control over how the 475 * tasks are run. 476 * 477 * This method must be invoked on the UI thread. 478 * 479 * @param params The parameters of the task. 480 * 481 * @return This instance of AsyncTask. 482 * 483 * @throws IllegalStateException If {@link #getStatus()} returns either 484 * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}. 485 */ 486 public final AsyncTask<Params, Progress, Result> execute(Params... params) { 487 return executeOnExecutor(sSerialExecutor, params); 488 } 489 490 /** 491 * Executes the task with the specified parameters. The task returns 492 * itself (this) so that the caller can keep a reference to it. 493 * 494 * This method must be invoked on the UI thread. 495 * 496 * @param exec The executor to use. {@link #THREAD_POOL_EXECUTOR} is available as a 497 * convenient process-wide thread pool for tasks that are loosely coupled. 498 * @param params The parameters of the task. 499 * 500 * @return This instance of AsyncTask. 501 * 502 * @throws IllegalStateException If {@link #getStatus()} returns either 503 * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}. 504 */ 505 public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, 506 Params... params) { 507 if (mStatus != Status.PENDING) { 508 switch (mStatus) { 509 case RUNNING: 510 throw new IllegalStateException("Cannot execute task:" 511 + " the task is already running."); 512 case FINISHED: 513 throw new IllegalStateException("Cannot execute task:" 514 + " the task has already been executed " 515 + "(a task can be executed only once)"); 516 } 517 } 518 519 mStatus = Status.RUNNING; 520 521 onPreExecute(); 522 523 mWorker.mParams = params; 524 exec.execute(mFuture); 525 526 return this; 527 } 528 529 /** 530 * Schedules the {@link Runnable} in serial with the other AsyncTasks that were started 531 * with {@link #execute}. 532 */ 533 public static void execute(Runnable runnable) { 534 sSerialExecutor.execute(runnable); 535 } 536 537 /** 538 * This method can be invoked from {@link #doInBackground} to 539 * publish updates on the UI thread while the background computation is 540 * still running. Each call to this method will trigger the execution of 541 * {@link #onProgressUpdate} on the UI thread. 542 * 543 * {@link #onProgressUpdate} will note be called if the task has been 544 * canceled. 545 * 546 * @param values The progress values to update the UI with. 547 * 548 * @see #onProgressUpdate 549 * @see #doInBackground 550 */ 551 protected final void publishProgress(Progress... values) { 552 if (!isCancelled()) { 553 sHandler.obtainMessage(MESSAGE_POST_PROGRESS, 554 new AsyncTaskResult<Progress>(this, values)).sendToTarget(); 555 } 556 } 557 558 private void finish(Result result) { 559 if (isCancelled()) { 560 onCancelled(result); 561 } else { 562 onPostExecute(result); 563 } 564 mStatus = Status.FINISHED; 565 } 566 567 private static class InternalHandler extends Handler { 568 @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) 569 @Override 570 public void handleMessage(Message msg) { 571 AsyncTaskResult result = (AsyncTaskResult) msg.obj; 572 switch (msg.what) { 573 case MESSAGE_POST_RESULT: 574 // There is only one result 575 result.mTask.finish(result.mData[0]); 576 break; 577 case MESSAGE_POST_PROGRESS: 578 result.mTask.onProgressUpdate(result.mData); 579 break; 580 } 581 } 582 } 583 584 private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { 585 Params[] mParams; 586 } 587 588 @SuppressWarnings({"RawUseOfParameterizedType"}) 589 private static class AsyncTaskResult<Data> { 590 final AsyncTask mTask; 591 final Data[] mData; 592 593 AsyncTaskResult(AsyncTask task, Data... data) { 594 mTask = task; 595 mData = data; 596 } 597 } 598} 599