private class DownloadFilesTask extends AsyncTask
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
这是一个下载的小例子,在doInBackgound这个方法中,大家注意看这句话,if (isCancelled()) break;它是写在了for循环里面的,平时大家下载的时候可能忘记这一点。加上这句话的话,就算我们正在下载中,也是可以直接跳出循环的,停止下载任务,这样更加保险。其他的方法大家都用的很多,这里就不再说了。
开启一下AsyncTask去下载更是非常简单:
new DownloadFilesTask().execute(url1, url2, url3);
(2)AsyncTask的范型类型。
一个异步任务使用的三种类型如下:
1:第一个参数是发送到doInBackground这个方法里面的。
2:进度类型。这个一般是我们在后台执行任务时,把进度通过publishProgress这个方法来发不出去,负责更新UI的。
3:最后一个参数是结果类型。当我们的doInBackground执行完毕的时候,负责回调onPostExecute方法,将参数传递到这个方法里面。
注意:不是我们所有传递的类型都会被异步任务使用,如果想要传递未被使用的类型,我们只需要传递Void。
private class MyTask extends AsyncTask
上面这种传递Void的写法,我们平时用的也很多。
(3):当一个异步任务执行时,通过4个步骤来执行。
1:onPreExecute,在任务执行前,调用UI线程,我们可以在这个方法里面更新UI界面。这一步通常用于设置任务,例如通过在用户界面显示一个进度条。
2:doInBackground,在onPreExecute这个方法调用完毕后,会立即在后台线程中调用。这个方法一般用来执行比较耗时的后台计算。异步任务的参数被传递到这个方法里面,后台任务执行完毕后必须返回计算的结果,并将结果传递到最后一个步骤中。这一步也可以使用publishprogress(Java Object。[ ])发布一个或多个单位的进展。这些值被公布在UI线程,在onProgressUpdate(Java Object。[ ])的步骤。
3:onProgressUpdate(Java Object。[ ])这个方法会在UI线程更新界面显示在调用publishprogress后(Java Object。[ ])。我们一般在doInBackground这个方法中调用publishprogress这个方法更新界面,例如我们可以用来更新下载进度条的进度。
4:在doInBackground这个方法执行完毕后会回调onPostExecute这个方法,并且将doInBackgound计算完毕后的结果以参数的形式传递到onPostExecute这个方法中。
(4):取消一个Task。
一个异步线程可以在任何时候通过调用cancel方法来取消。调用这个方法后,当我们调用isCancelled() 这个方法的时候会返回true。当我们调用cancel方法后,doInBackground这个方法执行完毕后将不会再调用onPostExecute这个方法,将会调用onCancelled这个方法。为了确保异步任务尽快的取消,如果可能的话(一个循环中),你应该始终检查isCancelled()这个方法的返回值。
(5)线程规则
为了让AsyncTask正常的工作,你应该遵守下面这几个规则。
1:AsyncTask必须在UI线程中开启(?why)。在android4.1.x及以上已经自动在UI线程中加载。(此处可能理解有误。)
2:Task的对象必须在UI线程中创建。(?why)
3:我们启动线程的execute这个方法,必须在UI线程中调用。
4:不要手动调用onPreExecute(), onPostExecute(java.lang.Object), doInBackground(java.lang.Object[]), onProgressUpdate(java.lang.Object[]) 这几个方法。
5:异步任务只能被执行一回,如果我们试图执行第二回的时候,会抛出一个异常。
(6)内存方面
1:AsyncTask保证所有的回调是同步的,除非你显示同步(这里理解为你自己去做同步);
2:没法翻译了。。。说白了,就是你按照正常的步骤走,不会出问题。
(7)执行顺序
1:当第一次介绍的时候,AsyncTask是一个后台执行的串行线程。但是从Build.VERSION_CODES.DONUT,android1.6开始,变成了一个后台并行执行的线程池。从Build.VERSION_CODES.HONEYCOMB,android3.0开始,又变成了任务在一个单一的线程中来执行,这是为了避免常见的并发错误。如果你真的想要的并行执行,你可以调用executeonexecutor与thread_pool_executor。
上面介绍完了AsyncTask要我们注意的事项,接下来我们就来分析AsyncTask的源代码,看看里面到底是一个什么东东。AsyncTask的源码并不多。我们先看它的成员变量。
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
181 private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
182 private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
183 private static final int KEEP_ALIVE = 1;
184
185 private static final ThreadFactory sThreadFactory = new ThreadFactory() {
186 private final AtomicInteger mCount = new AtomicInteger(1);
187
188 public Thread More ...newThread(Runnable r) {
189 return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
190 }
191 };
192
193 private static final BlockingQueue sPoolWorkQueue =
194 new LinkedBlockingQueue(128);
public static final Executor THREAD_POOL_EXECUTOR
200 = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
201 TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
208
209 private static final int MESSAGE_POST_RESULT = 0x1;
210 private static final int MESSAGE_POST_PROGRESS = 0x2;
211
212 private static final InternalHandler sHandler = new InternalHandler();
213
214 private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
215 private final WorkerRunnable mWorker;
216 private final FutureTask mFuture;
217
218 private volatile Status mStatus = Status.PENDING;
219
220 private final AtomicBoolean mCancelled = new AtomicBoolean();
221 private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
(1)cpu_count 这个就不用多说了,是在运行时获取手机的cpu的数量,例如我的手机双核,那么count就是2.
(2)CORE_POOL_SIZE,同一时刻能够运行的线程数的数量。当线程数量超过这个数目时,其他线程就要等待。
(3)MAXIMUM_POOL_SIZE,线程池的总大小,当我们试图添加超过这个数量的线程时,程序就会崩溃。
(4)KEEP_ALIVE,当前活跃的线程的数量,这里我们看到为1,也就是串行执行,这个后面就会在源代码看到为什么时串行执行。
(5)sThreadFactory,这是一个线程工厂。ThreadFactory是一个接口,我们直接new一个接口就相当于写了一个继承这个接口的子类。这样做的好处是我们就不用手动创建线程了,也就是不用自己去new Thread了。下面是一个简单的小例子。
package com.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
class Task implements Runnable{
int taskId;
public Task(int taskId) {
this.taskId=taskId;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"--taskId: "+taskId);
}
}
class DaemonThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
Thread t=new Thread(r);
t.setDaemon(true);
return t;
}
}
public class ThreadFactoryTest {
public static void main(String[] args) {
ExecutorService exec=Executors.newFixedThreadPool(3,new DaemonThreadFactory());
for(int i=0;i<3;i++) {
exec.submit(new Task(i));
}
exec.shutdown();
}
}
这里相信大家都明白了。
(6)sPoolWorkQueue,这个变量是从来存储Runnable的一个BlockingQueue
(7)THREAD_POOL_EXECUTOR,线程池,如果要AsyncTask并行执行的话,后面需要用到。
(8)MESSAGE_POST_RESULT,一个int型变量,在doInBackground方法执行完毕后,会通过handler将执行结果分发到onPostExecute这个方法里面,所以我们才可以在这个回调方法里面更新UI界面。
(9)MESSAGE_POST_PROGRESS,一个int型变量,当我们在doInBackground需要更新进度条显示的时候,需要通过handler分发消息,其中消息的what就是MESSAGE_POST_PROGRESS这个变量。
(10)sHandler,继承系统Handler实现的一个简单的handler类,用来分发消息到主线程,不然怎么更新界面。
(11)sDefaultExecutor,就是上面我们讲解的THREAD_POOL_EXECUTOR这个变量。
(12)mWorker,一个WorkerRunnable
private static abstract class WorkerRunnable implements Callable {
655 Params[] mParams;
656 }
一个自定义的抽象类,继承了Callable接口,这个接口中只有一个方法,下面看一下Callable接口的源代码。
public interface Callable {
64 V call() throws Exception;
65}
这里应该想到了,就是简单实现了一个接口,这样我们在其他的地方就可以调用call方法了。 这个方法中还有一个Result类型,我们看看这是个什么类型。
public abstract class AsyncTask {
(13)mFuture,这是一个FutureTask
public class FutureTask implements RunnableFuture {
public interface RunnableFuture extends Runnable, Future {
public interface More Future {
(14)mStatus,用来记录AsyncTask的运行状态,有PENDING, RUNNING,FINISHED,这三个状态,Pending状态说明AsyncTask还没有被执行,等待状态。Running正在执行状态。Finished完成状态。
(15)mCancelled,一个AtomicBoolean类型变量,解决线程同步问题。当前AsyncTask是否被取消。
(16)mTaskInvoked,一个AtomicBoolean类型变量,解决线程同步问题。当前AsyncTAsk是否被启动。
上面介绍完了AsyncTask的成员变量,下面我们就从AsyncTAsk的构造函数开始,一步一步分析AsyncTask是如何工作的,最后我们还要看看源代码,明白一下为什么我们使用AsyncTask要遵守Android我们定的准则,我们不遵守可以吗?
看看AsyncTask的构造函数:
public AsyncTask() {
282 mWorker = new WorkerRunnable() {
283 public Result call() throws Exception {
284 mTaskInvoked.set(true);
285
286 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
287 //noinspection unchecked
288 return postResult(doInBackground(mParams));
289 }
290 };
291
292 mFuture = new FutureTask(mWorker) {
293 @Override
294 protected void done() {
295 try {
296 postResultIfNotInvoked(get());
297 } catch (InterruptedException e) {
298 android.util.Log.w(LOG_TAG, e);
299 } catch (ExecutionException e) {
300 throw new RuntimeException("An error occured while executing doInBackground()",
301 e.getCause());
302 } catch (CancellationException e) {
303 postResultIfNotInvoked(null);
304 }
305 }
306 };
307 }
从构造方法中我们可以揣测到,mWorker这个对象一定在我们调用execute的时候会回调call方法,因为mTaskInvoked.set(true);这个标志为被设置成了true,说明AsyncTask被调用执行了。紧接着我们在后面的return语句后面发现了postResult(doInBackground(mParams));这句话,我擦,这不是我们doInBackground方法吗?把doInBackground方法的结果返回去了,反到哪里去了?不就是反到了我们平时调用的onPostExecute方法里面的参数了嘛。这个方法里面我们已经初步看到了一点蛛丝马迹。那么postResult这个方法里面是什么东东?
private Result postResult(Result result) {
317 @SuppressWarnings("unchecked")
318 Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
319 new AsyncTaskResult(this, result));
320 message.sendToTarget();
321 return result;
322 }
说到这里我们就继续看一眼sHandler这个handler里面的消息处理,顺序来吧,一回反回去,再讲解mFuture这个变量~ps:我喜欢顺序讲解,一步一步看。。。
private static class AsyncTaskResult {
660 final AsyncTask mTask;
661 final Data[] mData;
662
663 AsyncTaskResult(AsyncTask task, Data... data) {
664 mTask = task;
665 mData = data;
666 }
667 }
再看sHandler的源代码之前,先low一眼AsyncTaskResult这个类的代码,发现就是简单的两个成员变量~so easy
private static class InternalHandler extends Handler {
638 @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
639 @Override
640 public void handleMessage(Message msg) {
641 AsyncTaskResult result = (AsyncTaskResult) msg.obj;
642 switch (msg.what) {
643 case MESSAGE_POST_RESULT:
644 // There is only one result
645 result.mTask.finish(result.mData[0]);
646 break;
647 case MESSAGE_POST_PROGRESS:
648 result.mTask.onProgressUpdate(result.mData);
649 break;
650 }
651 }
652 }
好,在sHandler的重写的handleMessage方法中,我们可以看到最终的调用,MESSAGE_POST_RESULT这个消息下面,调用的是result.mTask.finish(result.mData[0]);而mTask就是当前的AsyncTask,接下来我们就看一下finish方法里面的调用。
private void finish(Result result) {
629 if (isCancelled()) {
630 onCancelled(result);
631 } else {
632 onPostExecute(result);
633 }
634 mStatus = Status.FINISHED;
635 }
果然不出所料,在finish方法里面根据isCancelled()方法调用onCancelled或者调用onPostExecute。豁然开朗啊,同理result.mTask.onProgressUpdate(result.mData);这句代码也就没有什么大惊小怪的了,这不就是更新进度显示的回调方法嘛!草,就是handler发送消息啊! 说了这么多,接下来我们该回到我们构造函数了。。。下面这个初始化变量我们还没有讲解~
mFuture = new FutureTask(mWorker) {
293 @Override
294 protected void done() {
295 try {
296 postResultIfNotInvoked(get());
297 } catch (InterruptedException e) {
298 android.util.Log.w(LOG_TAG, e);
299 } catch (ExecutionException e) {
300 throw new RuntimeException("An error occured while executing doInBackground()",
301 e.getCause());
302 } catch (CancellationException e) {
303 postResultIfNotInvoked(null);
304 }
305 }
306 };
这个我们猜测一下,我们构建了一个mWorker对象,里面有一个call的回调方法,然后我们mWorker对象通过FutureTask的构造函数传递进度,并且重写了里面的done方法。那mFuture里面一定会在重写的接口方法里面调用mWorker这个接口的call方法~那我们接下来看一下FutureTask的类的源代码吧。
public class FutureTask implements RunnableFuture {
64 private final Sync sync;
72
73 public FutureTask(Callable callable) {
74 if (callable == null)
75 throw new NullPointerException();
76 sync = new Sync(callable);
77 }
90
91 public FutureTask(Runnable runnable, V result) {
92 sync = new Sync(Executors.callable(runnable, result));
93 }
94
95 public boolean isCancelled() {
96 return sync.innerIsCancelled();
97 }
98
99 public boolean isDone() {
100 return sync.innerIsDone();
101 }
102
103 public boolean cancel(boolean mayInterruptIfRunning) {
104 return sync.innerCancel(mayInterruptIfRunning);
105 }
109
110 public V get() throws InterruptedException, ExecutionException {
111 return sync.innerGet();
112 }
116
117 public V get(long timeout, TimeUnit unit)
118 throws InterruptedException, ExecutionException, TimeoutException {
119 return sync.innerGet(unit.toNanos(timeout));
120 }
130
131 protected void done() { }
139
140 protected void set(V v) {
141 sync.innerSet(v);
142 }
151
152 protected void setException(Throwable t) {
153 sync.innerSetException(t);
154 }
155
156 // The following (duplicated) doc comment can be removed once
157 //
158 // 6270645: Javadoc comments should be inherited from most derived
159 // superinterface or superclass
160 // is fixed.
161
164
165 public void run() {
166 sync.innerRun();
167 }
176
177 protected boolean runAndReset() {
178 return sync.innerRunAndReset();
179 }
188
189 private final class Sync extends AbstractQueuedSynchronizer {
190 private static final long serialVersionUID = -7828117401763700385L;
State value representing that task is ready to run
192
193 private static final int READY = 0;
State value representing that task is running
194
195 private static final int RUNNING = 1;
State value representing that task ran
196
197 private static final int RAN = 2;
State value representing that task was cancelled
198
199 private static final int CANCELLED = 4;
The underlying callable
201
202 private final Callable callable;
The result to return from get()
203
204 private V result;
The exception to throw from get()
205
206 private Throwable exception;
212
213 private volatile Thread runner;
214
215 Sync(Callable callable) {
216 this.callable = callable;
217 }
218
219 private boolean ranOrCancelled(int state) {
220 return (state & (RAN | CANCELLED)) != 0;
221 }
225
226 protected int tryAcquireShared(int ignore) {
227 return innerIsDone() ? 1 : -1;
228 }
233
234 protected boolean tryReleaseShared(int ignore) {
235 runner = null;
236 return true;
237 }
238
239 boolean innerIsCancelled() {
240 return getState() == CANCELLED;
241 }
242
243 boolean innerIsDone() {
244 return ranOrCancelled(getState()) && runner == null;
245 }
246
247 V innerGet() throws InterruptedException, ExecutionException {
248 acquireSharedInterruptibly(0);
249 if (getState() == CANCELLED)
250 throw new CancellationException();
251 if (exception != null)
252 throw new ExecutionException(exception);
253 return result;
254 }
255
256 V innerGet(long nanosTimeout) throws InterruptedException, ExecutionException, TimeoutException {
257 if (!tryAcquireSharedNanos(0, nanosTimeout))
258 throw new TimeoutException();
259 if (getState() == CANCELLED)
260 throw new CancellationException();
261 if (exception != null)
262 throw new ExecutionException(exception);
263 return result;
264 }
265
266 void innerSet(V v) {
267 for (;;) {
268 int s = getState();
269 if (s == RAN)
270 return;
271 if (s == CANCELLED) {
272 // aggressively release to set runner to null,
273 // in case we are racing with a cancel request
274 // that will try to interrupt runner
275 releaseShared(0);
276 return;
277 }
278 if (compareAndSetState(s, RAN)) {
279 result = v;
280 releaseShared(0);
281 done();
282 return;
283 }
284 }
285 }
286
287 void innerSetException(Throwable t) {
288 for (;;) {
289 int s = getState();
290 if (s == RAN)
291 return;
292 if (s == CANCELLED) {
293 // aggressively release to set runner to null,
294 // in case we are racing with a cancel request
295 // that will try to interrupt runner
296 releaseShared(0);
297 return;
298 }
299 if (compareAndSetState(s, RAN)) {
300 exception = t;
301 releaseShared(0);
302 done();
303 return;
304 }
305 }
306 }
307
308 boolean innerCancel(boolean mayInterruptIfRunning) {
309 for (;;) {
310 int s = getState();
311 if (ranOrCancelled(s))
312 return false;
313 if (compareAndSetState(s, CANCELLED))
314 break;
315 }
316 if (mayInterruptIfRunning) {
317 Thread r = runner;
318 if (r != null)
319 r.interrupt();
320 }
321 releaseShared(0);
322 done();
323 return true;
324 }
325
326 void innerRun() {
327 if (!compareAndSetState(READY, RUNNING))
328 return;
329
330 runner = Thread.currentThread();
331 if (getState() == RUNNING) { // recheck after setting thread
332 V result;
333 try {
334 result = callable.call();
335 } catch (Throwable ex) {
336 setException(ex);
337 return;
338 }
339 set(result);
340 } else {
341 releaseShared(0); // cancel
342 }
343 }
344
345 boolean innerRunAndReset() {
346 if (!compareAndSetState(READY, RUNNING))
347 return false;
348 try {
349 runner = Thread.currentThread();
350 if (getState() == RUNNING)
351 callable.call(); // don't set result
352 runner = null;
353 return compareAndSetState(RUNNING, READY);
354 } catch (Throwable ex) {
355 setException(ex);
356 return false;
357 }
358 }
359 }
360}
这个类的代码稍微多一点,但是我们只需要找到我们关心的即可。我们首先找到构造函数~
73 public FutureTask(Callable callable) {
74 if (callable == null)
75 throw new NullPointerException();
76 sync = new Sync(callable);
77 }
FutureTask的构造函数需要我们传递进去一个实现Callable接口的对象,我们前面mWork对象已经实现了这个接口~。然后对callable对象进一步封装了一下,放到了Sync这个类里面,源代码里面的解释是这个类用来对FutureTask进行同步的控制,跟进去看一下这个类的构造函数~
Sync(Callable callable) {
216 this.callable = callable;
217 }
public final AsyncTask execute(Params... params) {
535 return executeOnExecutor(sDefaultExecutor, params);
536 }
这是AsyncTask的启动方法,继续跟进~
public final AsyncTask executeOnExecutor(Executor exec,
572 Params... params) {
573 if (mStatus != Status.PENDING) {
574 switch (mStatus) {
575 case RUNNING:
576 throw new IllegalStateException("Cannot execute task:"
577 + " the task is already running.");
578 case FINISHED:
579 throw new IllegalStateException("Cannot execute task:"
580 + " the task has already been executed "
581 + "(a task can be executed only once)");
582 }
583 }
584
585 mStatus = Status.RUNNING;
586
587 onPreExecute();
588
589 mWorker.mParams = params;
590 exec.execute(mFuture);
591
592 return this;
593 }
private static class SerialExecutor implements Executor {
224 final ArrayDeque mTasks = new ArrayDeque();
225 Runnable mActive;
226
227 public synchronized void execute(final Runnable r) {
228 mTasks.offer(new Runnable() {
229 public void run() {
230 try {
231 r.run();
232 } finally {
233 scheduleNext();
234 }
235 }
236 });
237 if (mActive == null) {
238 scheduleNext();
239 }
240 }
241
242 protected synchronized void scheduleNext() {
243 if ((mActive = mTasks.poll()) != null) {
244 THREAD_POOL_EXECUTOR.execute(mActive);
245 }
246 }
247 }
public interface Executor {
140 void execute(Runnable command);
141}
看来我们重写了里面的execute方法,好那我们就看一下SerialExecutor这个类重写的方法。不难看出,当我们传递一个Runnable进去之后,它重新封装成了一个新的Runnable接口,放到了ArrayDeque这个队列里面。下面有一个判断mActive是否为空,第一次肯定为空,那么就会调用scheduleNext方法,这个方法里面从ArrayDeque里面取出一个Runnable,然后放到了THREAD_POOL_EXECUTOR这个线程池里面去执行。在Runnable执行完毕后,无论如何都会在finally里面调用scheduleNext方法,这样假如我们队列里面有很多Runnable的话,就会串行执行下去。 我们再重新看一下THREAD_POOL_EXECUTOR这个变量~
public static final Executor THREAD_POOL_EXECUTOR
200 = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
201 TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
分析完了executeOnExecutor这个方法的参数,我们进一步看里面的实现~
if (mStatus != Status.PENDING) {
574 switch (mStatus) {
575 case RUNNING:
576 throw new IllegalStateException("Cannot execute task:"
577 + " the task is already running.");
578 case FINISHED:
579 throw new IllegalStateException("Cannot execute task:"
580 + " the task has already been executed "
581 + "(a task can be executed only once)");
582 }
583 }
584
585 mStatus = Status.RUNNING;
onPreExecute();
588
589 mWorker.mParams = params;
590 exec.execute(mFuture);
下面就是将传递进来的参数传递给mWorker对象的成员变量,而mWorker是封装在mFuture对象里面的,所以最后传递的是mFuture对象作为参数。exec执行的代码参考如下:再次贴一遍代码
public synchronized void execute(final Runnable r) {
228 mTasks.offer(new Runnable() {
229 public void run() {
230 try {
231 r.run();
232 } finally {
233 scheduleNext();
234 }
235 }
236 });
237 if (mActive == null) {
238 scheduleNext();
239 }
240 }
当然我们的mFuture是实现了Runnable接口的,所以肯定会重写run方法的,大家可以大胆的猜测一下,mFuture的run方法里面一定会调用mWorker的call方法,不然它怎么办~废话少说,看一下mFuture类中重写的的run方法~
public void run() {
166 sync.innerRun();
167 }
void innerRun() {
327 if (!compareAndSetState(READY, RUNNING))
328 return;
329
330 runner = Thread.currentThread();
331 if (getState() == RUNNING) { // recheck after setting thread
332 V result;
333 try {
334 result = callable.call();
335 } catch (Throwable ex) {
336 setException(ex);
337 return;
338 }
339 set(result);
340 } else {
341 releaseShared(0); // cancel
342 }
343 }
大家在334行看到没有,果然调用了mWorker的call方法,哈哈,说明我们的猜测完全正确~而call方法里面就是doInBackground的实现了,以后的逻辑就完全联系起来了。AsyncTask的整个过程就分析完了。 分析是分析完了,但是还有几个小小的疑问。
1:AsyncTask为什么必须在UI线程中execute?
因为在execute方法中会调用onPreExecute方法去更新界面,所以如果不是在UI线程中execute,那么程序就会崩溃。
2:AsyncTask为什么必须在UI线程中创建?
首先UI线程中创建而牵扯出的在AsyncTask中的成员变量,看了一下只有sHandler,而这个Handler的创建肯定会调用父类的默认的构造函数,那么我们就去看一眼handler默认的构造函数,看看里面是个什么东东~
public More ...Handler(Callback callback, boolean async) {
189 if (FIND_POTENTIAL_LEAKS) {
190 final Class extends Handler> klass = getClass();
191 if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
192 (klass.getModifiers() & Modifier.STATIC) == 0) {
193 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
194 klass.getCanonicalName());
195 }
196 }
197
198 mLooper = Looper.myLooper();
199 if (mLooper == null) {
200 throw new RuntimeException(
201 "Can't create handler inside thread that has not called Looper.prepare()");
202 }
203 mQueue = mLooper.mQueue;
204 mCallback = callback;
205 mAsynchronous = async;
206 }
public static Looper myLooper() {
162 return sThreadLocal.get();
163 }
发现有一个sThreadLocal,就是我们当前创建Handler的线程。然后我们继续跟进去~
public T get() {
143 Thread t = Thread.currentThread();
144 ThreadLocalMap map = getMap(t);
145 if (map != null) {
146 ThreadLocalMap.Entry e = map.getEntry(this);
147 if (e != null)
148 return (T)e.value;
149 }
150 return setInitialValue();
151 }
此时的范型T就是我们的Looper对象,我们就不再继续往里面跟了。发现最里面其实就是一个Map,我们可以根据我们的Thread来得到我们的Looper,对于没有Looper的Thread肯定是得不到Looper的。得不到Looper是不可能成功的创建Handler的,一创建就会报错~ 具体的关于Handler的请看我的另一篇博客:宇哥带你飞之handler~
好了,现在我们就有一个疑问了,我就要在子线程中使用AsyncTask,但是我给当前这个线程准备好Looper,这样Handler的创建肯定是没有问题的。难道是Android官方的表达不够严谨吗?下面我就写一个小例子来实验一下。系统4.0以上-编译sdk20
第一种写法:
private void init() {
content = (TextView) findViewById(R.id.content);
new Thread() {
@Override
public void run() {
Looper.prepare();
new AsyncTask() {
@Override
protected void onPreExecute() {
Log.d("xiaoyu","onPreExecute--"+Thread.currentThread().getId());
super.onPreExecute();
}
@Override
protected Void doInBackground(Void... params) {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Log.d("xiaoyu","onPostExecute--"+Thread.currentThread().getId());
Toast.makeText(MainActivity.this, "onPostExecute", Toast.LENGTH_LONG).show();
}
}.execute();
Looper.loop();
}
}.start();
}
继续实验:去掉Loop.prepare(),Loop.loop().再次运行程序,应该报错才对,为什么没有报错,难道我第一次写法,AsyncTask得到的根本就不是当前线程的looper?找问题,最后在ActivityThread中找到答案~
public static void main(String[] args) {
5009 SamplingProfilerIntegration.start();
5010
5011 // CloseGuard defaults to true and can be quite spammy. We
5012 // disable it here, but selectively enable it later (via
5013 // StrictMode) on debug builds, but using DropBox, not logs.
5014 CloseGuard.setEnabled(false);
5015
5016 Environment.initForCurrentUser();
5017
5018 // Set the reporter for event logging in libcore
5019 EventLogger.setReporter(new EventLoggingReporter());
5020
5021 Process.setArgV0("");
5022
5023 Looper.prepareMainLooper();
5024
5025 ActivityThread thread = new ActivityThread();
5026 thread.attach(false);
5027
5028 if (sMainThreadHandler == null) {
5029 sMainThreadHandler = thread.getHandler();
5030 }
5031
5032 AsyncTask.init();
5033
5034 if (false) {
5035 Looper.myLooper().setMessageLogging(new
5036 LogPrinter(Log.DEBUG, "ActivityThread"));
5037 }
5038
5039 Looper.loop();
5040
5041 throw new RuntimeException("Main thread loop unexpectedly exited");
5042 }
public static void init() {
sHandler.getLooper();
}
在主线程中创建的AsyTask得到的是主线程的Looper,这也就是为什么我们直接在没有Looper的子线程中创建AsyncTask的对象不会崩溃的原因。但是4.0一下的代码不保证AsyncTask一定是得到的是主线程的Looper,所以我们还是尽量不要在子线程中创建AsyncTask的对象。 2:接下来的问题是我们为什么必须在UI线程中调用execute方法呢?在子线程调用不行吗?从前面的分析中我们得到因为execute方法调用的时候会调用到onPreExecute方法,而这个方法我们一般都在里面更新界面,所以应该在子线程中调用execute方法,会崩溃才对~
new Thread() {
@Override
public void run() {
Log.d("xiaoyu","run--"+Thread.currentThread().getId());
new AsyncTask() {
@Override
protected void onPreExecute() {
Log.d("xiaoyu","onPreExecute--"+Thread.currentThread().getId());
super.onPreExecute();
content.setText("onPreExecute");
}
@Override
protected Void doInBackground(Void... params) {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Log.d("xiaoyu","onPostExecute--"+Thread.currentThread().getId());
Toast.makeText(MainActivity.this, "onPostExecute", Toast.LENGTH_LONG).show();
}
}.execute();
}
}.start();
08-05 10:48:17.810 2406-2406/? D/xiaoyu﹕ mainThreadId--1
08-05 10:48:17.810 2406-2424/? D/xiaoyu﹕ run--178
08-05 10:48:17.810 2406-2424/? D/xiaoyu﹕ onPreExecute--178
08-05 10:48:17.926 2406-2406/? D/xiaoyu﹕ onPostExecute--1