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