我们都会有这样的需求,比如从网络上进行耗时的操作然后拿到数据,然后把数据更新到UI上,我们一般的做法就是在子线程中进行耗时的操作,然后在主线程中进行UI的更新,如果要是在UI线程中进行耗时的操作可能会导致ANR的发生。
Android中已经为我们封装好了一个类--AsyncTask,它内部实现主要就是Handler+Thread,接下来让我们一起看看源码来了解一下用法。
在查看源码时,我们先从类的注解看起。
* <p>AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
* and does not constitute a generic threading framework. AsyncTasks should ideally be
* used for short operations (a few seconds at the most.) If you need to keep threads
* running for long periods of time, it is highly recommended you use the various APIs
* provided by the <code>java.util.concurrent</code> package such as {@link Executor},
* {@link ThreadPoolExecutor} and {@link FutureTask}.</p>
这段源码告诉我们,AsyncTask的内部实现是Handler+Thread,它只适应于短时间(几秒钟)的耗时操作,而不适应于长时间的耗时操作,若需要长时间的操作,可以用Executor、ThreadPoolExecutore、FutureTask。
<p>An asynchronous task is defined by a computation that runs on a background thread and
* whose result is published on the UI thread. An asynchronous task is defined by 3 generic
* types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>,
* and 4 steps, called <code>onPreExecute</code>, <code>doInBackground</code>,
* <code>onProgressUpdate</code> and <code>onPostExecute</code>.</p>
这段源码讲,它的数据获取在子线程中,最终结果的处理会在UI线程中,它是一个抽象的泛型类
public abstract class AsyncTask<Params, Progress, Result> {
里面有三个泛型参数:
<li><code>Params</code>, the type of the parameters sent to the task upon
* execution.</li>
* <li><code>Progress</code>, the type of the progress units published during
* the background computation.</li>
* <li><code>Result</code>, the type of the result of the background
* computation.</li>
Params:参数的类型
Progress:当前进度的类型
Result:返回结果的类型
注解中提到重要的4个核心方法:
<li>{@link #onPreExecute()}, invoked on the UI thread before the task
* is executed. This step is normally used to setup the task, for instance by
* showing a progress bar in the user interface.</li>
* <li>{@link #doInBackground}, invoked on the background thread
* immediately after {@link #onPreExecute()} finishes executing. This step is used
* to perform background computation that can take a long time. The parameters
* of the asynchronous task are passed to this step. The result of the computation must
* be returned by this step and will be passed back to the last step. This step
* can also use {@link #publishProgress} to publish one or more units
* of progress. These values are published on the UI thread, in the
* {@link #onProgressUpdate} step.</li>
* <li>{@link #onProgressUpdate}, invoked on the UI thread after a
* call to {@link #publishProgress}. The timing of the execution is
* undefined. This method is used to display any form of progress in the user
* interface while the background computation is still executing. For instance,
* it can be used to animate a progress bar or show logs in a text field.</li>
* <li>{@link #onPostExecute}, invoked on the UI thread after the background
* computation finishes. The result of the background computation is passed to
* this step as a parameter.</li>
onPreExecute:在主线程中执行,在异步任务执行之前被调用,主要是用于进行一些初始化的工作
doInBackground:在子线程中执行,在onPreExecute之后执行,主要用于做一些耗时的操作,返回的结果最终会交给onPostExecute,也可以调用publishProgress来更新进度,然后回调onProgressUpdate
onProgressUpdate:在主线程中执行,主要是对publishProgress中返回的进度进行处理
onPostExecute:在主线程中执行,对doInBackground返回的结果进行处理
接下来看一下官方给出的一个例子:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
* 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");
* }
* }
使用方法:
在线程中加入下面代码:
new DownloadFilesTask().execute(url1, url2, url3);
接下来我们就开始进入分析AsyncTask工作的逻辑处理:
首先看AsyncTask的构造方法:
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
FutureTask实现了Future、Runnbale接口,它的get()方法是支持阻塞的,而且它的构造函数中支持传进CallBack类型的参数:
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
所以带有返回值,介于这两点,futureTask可以被用来作为
预加载数据处理
在这里,Future是对mWoker进行封装,当做Runnable来处理
然后看execute():
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
调用了executeOnExecutor(),里面sDefaultExecutor参数是SerialExecuotr的一个实例:
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
可以看出,SerialExecutor实现啦Executor接口,在execute方法中,它首先把参数Runnable r加入到一个双向队列mTasks中,mActive是判断当前是否有正在运行的AsyncTask,如果没有就会从mTasks中拿出一个Runnable,然后用THREAD_POOL_EXECUTOR线程池来执行该Runnable,当当前的AsyncTask执行完成后会执行下一个Runnable,直到mTask中所有的Runnable执行完成。可以看出,在默认的情况下,AsyncTask是串行执行的。
上面讲到最终执行是通过THREAD_POOL_EXECUTOR来执行任务的:
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
可以看到THREAD_POOL_EXECUTOR其实就是ThreadPoolExecutor的一个实例,它定义了一个
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
核心线程数为:CPU数量+1;
最大线程数为:CPU*2+1;
超时时长为:1s
回到executeOnExecutor():
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
这里调用了onPreExecute(),所以要在主线程中对AsyncTask进行初始化,这样onPreExecute()就是在主线程中进行调用。
上面讲到过mFuture中封装了mWorker,所以mFuture中也就有了params。
然后就是调用上面说的SerialExecutor.execute();
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
再来看看这个方法,这里的Runnable r 参数其实就是FutureTask,r.run()方法就是FutureTask.run();
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
还记得在
public
FutureTask(Callable<
V
> callable);中 this.callable = callable;
所以这里的 c就是mWorker,然后就调用c.call():
还记得在AsyncTask构造方法中:
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
这里调用了doInBackground(mParam); doInBackground()是AsyncTask中的抽象方法,所以必须被子类所重写,可以看到call()方法是在子线程中被调用的,所以doInBackground是在子线程中进行处理的,所以就可以在方法中进行耗时的操作,记得在doInBackground()中可以调用publishProgress():
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
getHandler()返回handler:
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
可以看到handler是InternalHandler类型的;
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
从构造方法中可以看到,handler中的消息是在主线程中进行处理的
result.mTask返回的是:result所对应的FutureTask
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
可以看到这里接收了两种消息:
1)MESSAGE_POST_RESULT:
调用FutureTask.finish();
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
如果AsyncTask被取消了,就执行onCancelled()
否则就执行onPostExecute()
2)MESSAGE_POST_PROGRESS:
调用onProgressUpdate();
回过头看mWorker中call()方法中的postResult();
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
这里就是发送一个msg.what为MESSAGE_POST_RESULT的消息,然后就是在InternalHandler中进行处理。
到这里,差不多所有的逻辑都走通啦,但是还有一些注意事项和用法:
1)我们在使用时,最好不要自己去调用4大核心方法,否则会有想不到的错误
2)AsyncTask默认情况下是串行执行的,但我们可以主动调用executeOnExecutro()来实现并行执行
好啦,到这里差不多结束啦,谢谢大家的浏览,如果有疑问与不足之处,望请提出,我们共同学习!