DisplayingBitmaps / src / com.example.android.displayingbitmaps / util /

AsyncTask.java

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&lt;URL, Integer, Long&gt; {
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&lt;Void, Void, Void&gt; { ... }
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
}