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