3232import java .util .concurrent .atomic .AtomicInteger ;
3333
3434/**
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>
35+ * <p>AsyncTask enables proper and easy use of the UI thread (also called main thread) or
36+ * any other looper thread. AsyncTask is most commonly used to interact with the UI thread.
37+ * This class allows to perform background operations and publish results on a looper
38+ * thread without having to manipulate threads and/or handlers.</p>
3839 *
3940 * <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+ * whose result is published on a looper thread. An asynchronous task is defined by 3 generic
4142 * types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>,
4243 * and 4 steps, called <code>onPreExecute</code>, <code>doInBackground</code>,
4344 * <code>onProgressUpdate</code> and <code>onPostExecute</code>.</p>
101102 * <h2>The 4 steps</h2>
102103 * <p>When an asynchronous task is executed, the task goes through 4 steps:</p>
103104 * <ol>
104- * <li>{@link #onPreExecute()}, invoked on the UI thread immediately after the task
105+ * <li>{@link #onPreExecute()}, invoked on the looper thread immediately after the task
105106 * is executed. This step is normally used to setup the task, for instance by
106107 * showing a progress bar in the user interface.</li>
107108 * <li>{@link #doInBackground}, invoked on the background thread
110111 * of the asynchronous task are passed to this step. The result of the computation must
111112 * be returned by this step and will be passed back to the last step. This step
112113 * can also use {@link #publishProgress} to publish one or more units
113- * of progress. These values are published on the UI thread, in the
114+ * of progress. These values are published on the looper thread, in the
114115 * {@link #onProgressUpdate} step.</li>
115- * <li>{@link #onProgressUpdate}, invoked on the UI thread after a
116+ * <li>{@link #onProgressUpdate}, invoked on the looper thread after a
116117 * call to {@link #publishProgress}. The timing of the execution is
117118 * undefined. This method is used to display any form of progress in the user
118119 * interface while the background computation is still executing. For instance,
119120 * it can be used to animate a progress bar or show logs in a text field.</li>
120- * <li>{@link #onPostExecute}, invoked on the UI thread after the background
121+ * <li>{@link #onPostExecute}, invoked on the looper thread after the background
121122 * computation finishes. The result of the background computation is passed to
122123 * this step as a parameter.</li>
123124 * </ol>
135136 * <p>There are a few threading rules that must be followed for this class to
136137 * work properly:</p>
137138 * <ul>
138- * <li>The task instance must be created on the UI thread.</li>
139- * <li>{@link #execute} must be invoked on the UI thread.</li>
139+ * <li>The task instance must be created on the looper thread.</li>
140+ * <li>{@link #execute} must be invoked on the looper thread.</li>
140141 * <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute},
141142 * {@link #doInBackground}, {@link #onProgressUpdate} manually.</li>
142143 * <li>The task can be executed only once (an exception will be thrown if
152153 * <li>Set member fields in {@link #doInBackground}, and refer to them in
153154 * {@link #onProgressUpdate} and {@link #onPostExecute}.
154155 * </ul>
156+ *
157+ * @see Looper
158+ * @see Handler
155159 */
156160public abstract class AsyncTask <Params , Progress , Result > {
157161 private static final String LOG_TAG = "AsyncTask" ;
@@ -187,7 +191,13 @@ public Thread newThread(Runnable r) {
187191 private static final int MESSAGE_POST_RESULT = 0x1 ;
188192 private static final int MESSAGE_POST_PROGRESS = 0x2 ;
189193
190- private static final InternalHandler sHandler = new InternalHandler ();
194+ private static final ThreadLocal <InternalHandler > sHandler =
195+ new ThreadLocal <InternalHandler >() {
196+ @ Override
197+ protected InternalHandler initialValue () {
198+ return new InternalHandler ();
199+ }
200+ };
191201
192202 private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR ;
193203 private final WorkerRunnable <Params , Result > mWorker ;
@@ -196,6 +206,7 @@ public Thread newThread(Runnable r) {
196206 private volatile Status mStatus = Status .PENDING ;
197207
198208 private final AtomicBoolean mTaskInvoked = new AtomicBoolean ();
209+ private final InternalHandler mHandler ;
199210
200211 private static class SerialExecutor implements Executor {
201212 final ArrayDeque <Runnable > mTasks = new ArrayDeque <Runnable >();
@@ -242,9 +253,8 @@ public enum Status {
242253 FINISHED ,
243254 }
244255
245- /** @hide Used to force static handler to be created. */
256+ /** @hide */
246257 public static void init () {
247- sHandler .getLooper ();
248258 }
249259
250260 /** @hide */
@@ -253,9 +263,20 @@ public static void setDefaultExecutor(Executor exec) {
253263 }
254264
255265 /**
256- * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
266+ * Creates a new asynchronous task. This constructor must be invoked on the looper thread.
267+ *
268+ * @throws IllegalStateException if this constructor is invoked on a non-looper thread
269+ *
270+ * @see Looper
257271 */
258272 public AsyncTask () {
273+ if (Looper .myLooper () == null ) {
274+ throw new IllegalStateException ("AsyncTask can be only instanciated on a "
275+ + "looper thread. The current thread is " + Thread .currentThread ());
276+ }
277+
278+ mHandler = sHandler .get ();
279+
259280 mWorker = new WorkerRunnable <Params , Result >() {
260281 public Result call () throws Exception {
261282 mTaskInvoked .set (true );
@@ -295,7 +316,12 @@ private void postResultIfNotInvoked(Result result) {
295316 }
296317
297318 private Result postResult (Result result ) {
319+ <<<<<<< HEAD
298320 Message message = sHandler .obtainMessage (MESSAGE_POST_RESULT ,
321+ =======
322+ @ SuppressWarnings ({"unchecked" })
323+ Message message = mHandler .obtainMessage (MESSAGE_POST_RESULT ,
324+ >>>>>>> 6 c0d0b8 ... Check whether an AsyncTask is created /executed on a looper thread .
299325 new AsyncTaskResult <Result >(this , result ));
300326 message .sendToTarget ();
301327 return result ;
@@ -316,7 +342,7 @@ public final Status getStatus() {
316342 * by the caller of this task.
317343 *
318344 * This method can call {@link #publishProgress} to publish updates
319- * on the UI thread.
345+ * on the looper thread.
320346 *
321347 * @param params The parameters of the task.
322348 *
@@ -329,7 +355,7 @@ public final Status getStatus() {
329355 protected abstract Result doInBackground (Params ... params );
330356
331357 /**
332- * Runs on the UI thread before {@link #doInBackground}.
358+ * Runs on the looper thread before {@link #doInBackground}.
333359 *
334360 * @see #onPostExecute
335361 * @see #doInBackground
@@ -338,7 +364,7 @@ protected void onPreExecute() {
338364 }
339365
340366 /**
341- * <p>Runs on the UI thread after {@link #doInBackground}. The
367+ * <p>Runs on the looper thread after {@link #doInBackground}. The
342368 * specified result is the value returned by {@link #doInBackground}.</p>
343369 *
344370 * <p>This method won't be invoked if the task was cancelled.</p>
@@ -354,7 +380,7 @@ protected void onPostExecute(Result result) {
354380 }
355381
356382 /**
357- * Runs on the UI thread after {@link #publishProgress} is invoked.
383+ * Runs on the looper thread after {@link #publishProgress} is invoked.
358384 * The specified values are the values passed to {@link #publishProgress}.
359385 *
360386 * @param values The values indicating progress.
@@ -367,7 +393,7 @@ protected void onProgressUpdate(Progress... values) {
367393 }
368394
369395 /**
370- * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
396+ * <p>Runs on the looper thread after {@link #cancel(boolean)} is invoked and
371397 * {@link #doInBackground(Object[])} has finished.</p>
372398 *
373399 * <p>The default implementation simply invokes {@link #onCancelled()} and
@@ -390,7 +416,7 @@ protected void onCancelled(Result result) {
390416 * This method is invoked by the default implementation of
391417 * {@link #onCancelled(Object)}.</p>
392418 *
393- * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
419+ * <p>Runs on the looper thread after {@link #cancel(boolean)} is invoked and
394420 * {@link #doInBackground(Object[])} has finished.</p>
395421 *
396422 * @see #onCancelled(Object)
@@ -425,7 +451,7 @@ public final boolean isCancelled() {
425451 * an attempt to stop the task.</p>
426452 *
427453 * <p>Calling this method will result in {@link #onCancelled(Object)} being
428- * invoked on the UI thread after {@link #doInBackground(Object[])}
454+ * invoked on the looper thread after {@link #doInBackground(Object[])}
429455 * returns. Calling this method guarantees that {@link #onPostExecute(Object)}
430456 * is never invoked. After invoking this method, you should check the
431457 * value returned by {@link #isCancelled()} periodically from
@@ -498,14 +524,15 @@ public final Result get(long timeout, TimeUnit unit) throws InterruptedException
498524 * with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings on
499525 * its use.
500526 *
501- * <p>This method must be invoked on the UI thread.
527+ * <p>This method must be invoked on the looper thread.
502528 *
503529 * @param params The parameters of the task.
504530 *
505531 * @return This instance of AsyncTask.
506532 *
507533 * @throws IllegalStateException If {@link #getStatus()} returns either
508- * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
534+ * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED} or
535+ * the current thread is not a looper thread.
509536 */
510537 public final AsyncTask <Params , Progress , Result > execute (Params ... params ) {
511538 return executeOnExecutor (sDefaultExecutor , params );
@@ -531,7 +558,7 @@ public final AsyncTask<Params, Progress, Result> execute(Params... params) {
531558 * executed in serial; to guarantee such work is serialized regardless of
532559 * platform version you can use this function with {@link #SERIAL_EXECUTOR}.
533560 *
534- * <p>This method must be invoked on the UI thread.
561+ * <p>This method must be invoked on the looper thread.
535562 *
536563 * @param exec The executor to use. {@link #THREAD_POOL_EXECUTOR} is available as a
537564 * convenient process-wide thread pool for tasks that are loosely coupled.
@@ -540,10 +567,16 @@ public final AsyncTask<Params, Progress, Result> execute(Params... params) {
540567 * @return This instance of AsyncTask.
541568 *
542569 * @throws IllegalStateException If {@link #getStatus()} returns either
543- * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
570+ * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED} or
571+ * the current thread is not a looper thread.
544572 */
545573 public final AsyncTask <Params , Progress , Result > executeOnExecutor (Executor exec ,
546574 Params ... params ) {
575+ if (Looper .myLooper () == null ) {
576+ throw new IllegalStateException ("AsyncTask can be only instanciated on a "
577+ + "looper thread. The current thread is " + Thread .currentThread ());
578+ }
579+
547580 if (mStatus != Status .PENDING ) {
548581 switch (mStatus ) {
549582 case RUNNING :
@@ -576,9 +609,9 @@ public static void execute(Runnable runnable) {
576609
577610 /**
578611 * This method can be invoked from {@link #doInBackground} to
579- * publish updates on the UI thread while the background computation is
612+ * publish updates on the looper thread while the background computation is
580613 * still running. Each call to this method will trigger the execution of
581- * {@link #onProgressUpdate} on the UI thread.
614+ * {@link #onProgressUpdate} on the looper thread.
582615 *
583616 * {@link #onProgressUpdate} will note be called if the task has been
584617 * canceled.
@@ -590,7 +623,7 @@ public static void execute(Runnable runnable) {
590623 */
591624 protected final void publishProgress (Progress ... values ) {
592625 if (!isCancelled ()) {
593- sHandler .obtainMessage (MESSAGE_POST_PROGRESS ,
626+ mHandler .obtainMessage (MESSAGE_POST_PROGRESS ,
594627 new AsyncTaskResult <Progress >(this , values )).sendToTarget ();
595628 }
596629 }
0 commit comments