上一篇我们讲解了Handler
的相关知识,这篇文章就在来对AsyncTask
进行讲解。
那么,什么是AsyncTask
呢?AsyncTask是一种轻量级的异步线程类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程更新UI。简单来说AsyncTask也就是对Handler和线程池的封装。
我们先来看下AsyncTask
的一个简单例子:
1 AsyncTask asyncTask = new AsyncTask() {
2 @Override
3 protected String doInBackground(String... params) {
4 return params[0];
5 }
6 @Override
7 protected void onProgressUpdate(Integer... values) {
8 progressBar.setProgress(values[0]*100/1000);
9 }
10 @Override
11 protected void onPostExecute(String s) {
12 Log.e("LHC", "result:"+ s);
13 }
14 @Override
15 protected void onPreExecute() {
16 //TODO
17 }
18 };
19 asyncTask.execute("AsyncTask 测试");
- 第
1
行:生成了一个AsyncTask
类对象,而AsyncTask
是一个抽象类,具体定义为AsyncTask
,其中参数Params
为在执行任务时,发送给任务的参数类型,也就是方法doInBackground
的参数类型;参数Progress
为后台执行期间的进度类型,也就是方法onProgressUpdate
的参数类型;参数Result
为后台执行的结果类型,也就是方法onPostExecute
的参数类型。 - 第
2~5
行:doInBackground(Params... params)
方法,在方法中定义后台线程要执行的任务,参数在执行任务也就是调用execute(Params... params)
时传入;在方法中可以执行publishProgress(Progress... values)
方法,用来更新UI。 - 第
6~9
行:onProgressUpdate(Progress... values)
方法,在UI中用来更新任务进度,由publishProgress(Progress... values)
方法内部进行调用。 - 第
10~13
行:onPostExecute(Result result)
方法,在UI线程中用于保存或者显示结果。参数result
是doInBackground
执行后的返回结果。 - 第
14~17
行:onPreExecute()
方法,用于做一些准备工作。在doInBackground
方法之前调用。 - 第
19
行:execute(Params... params)
方法,执行任务,params
就是要传入的参数值。
这样就完成了AsyncTask
的简单使用,下面我们就看看源码内部的实现。看第1
行代码new AsyncTask
中的代码实现:
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
this((Looper) null);
}
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*
* @hide
*/
public AsyncTask(@Nullable Looper callbackLooper) {
1 mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
2 mWorker = new WorkerRunnable() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
3 result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
4 postResult(result);
}
return result;
}
};
5 mFuture = new FutureTask(mWorker) {
@Override
protected void done() {
try {
6 postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
7 postResultIfNotInvoked(null);
}
}
};
}
需要注意的是,代码中的两个构造方法都需要在主线程中运行,看两个方法的注释。
代码最终调用到了带参数的AsyncTask(@Nullable Looper callbackLooper)
构造函方法,具体分析如下:
- 第
1
行:根据传入的callbackLooper
参数是否为空或者是否为Looper.getMainLooper()
也就是主线程的Looper
值,来生成一个Handler
对象;当为空或者值相等时,调用了getMainHandler()
方法;当不为空或者值不相等时,调用了new Handler(callbackLooper)
。
而getMainHandler()
方法,具体代码为:
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@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;
}
}
}
方法中生成了一个InternalHandler
类对象,传入的是主线程的Looper
值。在看InternalHandler
类中,在handleMessage
中处理了得到的消息。这里的消息有两种类型MESSAGE_POST_RESULT
和MESSAGE_POST_PROGRESS
。
为MESSAGE_POST_RESULT
时,执行了finish
方法,代码为:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
在if语句中判断isCancelled
的值,也就是任务是否取消来决定执行取消任务还是调用返回结果的方法onPostExecute
。最后将任务状态设置为FINISHED
。
为MESSAGE_POST_PROGRESS
时,执行了onProgressUpdate
方法,用来更新任务执行的进度。
- 第
2,3,4
行:生成了一个WorkerRunnable
对象mWorker
,而这个类是个抽象类并且实现了Callable
接口,因此mWorker
也就是一个线程类。在call()
方法中设置了线程的优先级,并调用了doInBackground(mParams)
方法用来执行后台任务;如果出现异常就调用postResult(result)
方法。
postResult(result)
方法的具体代码如下:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();
return result;
}
在这个方法中发送了一条消息类型为MESSAGE_POST_RESULT
的消息。
- 第
5,6,7
行:将上面得到的mWorker
作为参数生成了一个FutureTask
对象mFuture
,而FutureTask
类实现了RunnableFuture
接口,而RunnableFuture
又实现了Runnable, Future
接口,因此mFuture
也可以看做是一个线程。接下来在FutureTask
下的done
方法中调用了postResultIfNotInvoked(get())
方法。
postResultIfNotInvoked(get())
方法的具体代码如下:
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
这个方法用来判定是否已经执行过postResult(result)
方法。
看第19
行代码asyncTask.execute("AsyncTask 测试")
中的代码实现:
@MainThread
public final AsyncTask execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@MainThread
public final AsyncTask 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;
}
需要注意的是,这两个执行方法也是需要是主线程中执行的。
执行代码最终进入了executeOnExecutor
执行方法。此方法中现根据任务的mStatus
状态值,判定任务是否正在执行或者已经执行过了,如果正在执行或者已经执行过了,就不能在调用执行方法进行执行了,也就是一个AsyncTask任务只能执行一次
;如果没有执行过,将任务状态改为正在执行,然后调用onPreExecute()
做执行任务前的准备工作,在将传入的参数赋值给mWorker
中的mParams
变量,最后线程池exec
执行线程mFuture
。这里的exec
也就是sDefaultExecutor
,定义如下:
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();
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,并且给这个方法加了同步锁,而sDefaultExecutor是SerialExecutor的对象,所以这个线程池也就是一个串行的线程池,任务一个执行完成后另一个才能执行
。方法execute
中,将生成的新任务加入到mTasks
任务队列尾部,而在新任务中执行了r.run()
方法,此方法为调用exec.execute(mFuture)
中传入的mFuture
中的run
方法,而在这个run
方法中执行了mWorker
中的call()
方法,这样后台线程也就开始执行了。执行完r.run()
之后,又执行了scheduleNext()
方法。在这个方法中,通过调用mTasks.poll()
方法,删除并获取队列中第一个元素的值,将其赋值mActive
,如果值不为空,使用线程池THREAD_POOL_EXECUTOR
执行线程mActive
;为空则退出。
这样AsyncTask
的一整套流程就走完了,但是需要注意的是execute方法默认是串行执行的,也就是一个任务执行完了,另一个才能执行;如果你不想等待一个任务执行完成就去执行另一个任务,该怎么办呢?这时就需要调用executeOnExecutor方法,并传入系统为我们准备好的并行执行的线程池AsyncTask.THREAD_POOL_EXECUTOR,这样就完成了任务的并行执行。
简单的例子如下:
/**
* 调用“execute”在程序还未执行完时,退出;那么子线程会在后台继续执行,直到执行完成;
* 当子线程在没有执行完成时,在此调用“execute”方法,此时新建立的子线程并不会执行,只有等上一个子线程执行完成后才能执行。
* 因为这个方法中的线程池“AsyncTask.SERIAL_EXECUTOR”是串行执行的。
*/
task.execute("Use Test of AsyncTask.", "1000");
/**
* 调用“executeOnExecutor”在程序还未执行完时,退出;子线程在后台继续运行;
* 当子线程在没有执行完成时,在此调用“executeOnExecutor”方法,新建立的子线程立刻执行。
* 因为这个方法中的线程池“AsyncTask.THREAD_POOL_EXECUTOR”是并行执行的
*/
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "Use Test of AsyncTask.", "1000");
在上面的代码中,也注释了使用并行的一种情况。