在Android开发中经常会通过线程去执行耗时的任务,并且在任务执行完之后通常会用到Handler来更新UI。虽然实现简单,但是有多个任务同时执行时则会显得代码很臃肿。Android提供了AsyncTask,它使得异步任务实现起来更加简单,代码更简洁。
AsyncTask是一个抽象的泛型类,它有3个泛型参数,分别为Params、Progress和Result。
Params:参数类型,
Progress:后台任务执行进度的类型,
Result:返回结果的类型。
如果不需要某个参数,可以将其设置为Void类型。
AsyncTask如下:
public abstract class AsyncTask {
}
AsyncTask中有4个核心方法:
1、onPreExecute():在主线程中执行。一般在任务执行前做准备工作。
2、doInBackground(Params…params):在线程池中执行。在 onPreExecute方法执行后运行,用来执行耗时操作。在执行过程中可以调用publishProgress(Progress…values)方法来更新进度信息。
3、onProgressUpdate(Progress…values):在主线程中执行。当调用publishProgress(Progress…values)方法时,此方法会将进度更新到UI组件上。
4、onPostExecute(Result result):在主线程中执行。当后台任务执行完成后,会被执行。doInBackground方法得到的结果就是返回的result的值。
接下来分析一下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 Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*
* @hide
*/
public AsyncTask(@Nullable Looper callbackLooper) {
//对mHandler和callbackLooper判空
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
mWorker = new WorkerRunnable() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);//在call方法中调用了doInBackground(mParams)来处理任务并得到结果
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);//最终调用postResult将结果投递出去
}
return result;
}
};
//FutureTask是一个可管理的异步任务
mFuture = new FutureTask(mWorker) {//在这里WorkerRunnable作为参数传递给了FutureTask
@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 occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
WorkerRunnable实现call方法,在call方法中调用了doInBackground(mParams)来处理任务并得到结果,并最终调用postResult将结果通过Handler发出去。
FutureTask实现了Runnable和Futrue这两个接口。因此,它可以包装Runnable和Callable,并提供给Executor执行。也可以调用FutureTask自己的run()方法执行。代码如下:
public class FutureTask implements RunnableFuture {
...
}
FutureTask实现RunnableFuture接口
public interface RunnableFuture extends Runnable, Future {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
RunnableFuture继承Runnable, Future两个接口。
当要执行 AsyncTask 时,需要调用它的 execute方法,代码如下:
@MainThread
public final AsyncTask execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
execute方法中又调用了executeOnExecutor方法:
@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;//将 AsyncTask 的参数传给WorkerRunnable
exec.execute(mFuture);//exec是传进来的参数sDefaultExecutor
return this;
}
这里会首先调用 onPreExecute 方法,将 AsyncTask 的参数传给WorkerRunnable。
从前面我们知道WorkerRunnable作为参数传递给了FutureTask,因此,参数被封装到FutureTask中。接下来
会调用exec的execute方法,并将mFuture也就是前面讲到的FutureTask传进去。
exec是传进来的参数sDefaultExecutor,是一个串行的线程池,SerialExecutor代码如下:
private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();
Runnable mActive;
public synchronized void execute(final Runnable r) {//串行执行
mTasks.offer(new Runnable() {//将FutureTask加入到mTasks中,r就是前面传进来的mFuture,mFuture就是Futrue对象
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {//从 mTasks 取出 FutureTask任务
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
从上面代码可以看出,当调用SerialExecutor 的execute方法时,会将FutureTask加入到mTasks中。当任务执行完或者当前没有活动的任务时都会执行SerialExecutor里面的scheduleNext方法,它会从 mTasks 取出 FutureTask任务并交由 THREAD_POOL_EXECUTOR 处理。
加了synchronized关键字,所以SerialExecutor是串行执行的。可以看到执行了FutureTask的run方法,它最终会调
用WorkerRunnable的call方法。前面我们提到call方法最终会调用postResult方法将结果投递出去,postResult
方法的代码如下:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();
return result;
}
在postResult方法中会创建Message,将结果赋值给这个Message,通过getHandler方法得到Handler,并
通过这个Handler发送消息。getHandler方法如下所示:
private Handler getHandler() {
return mHandler;
}
在getHandler方法中直接返回mHandler,在之前构造方法的时候判断mHandler==null时调用getMainHandler(),getMainHandler()代码如下所示:
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
在getMainHandler方法中创建了InternalHandler,InternalHandler的定义如下:
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;
}
}
}
在接收到MESSAGE_POST_RESULT消息后会调用AsyncTask的finish方法,代码如下:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
如果AsyncTask任务被取消了,则执行onCancelled方法,否则就调用onPostExecute方法。正是通过
onPostExecute 方法,我们才能够得到异步任务执行后的结果。
接着回头来看SerialExecutor,线程池SerialExecutor主要用来处理排队,将任务串行处理。在SerialExecutor中调用 scheduleNext 方法时,将任务交给 THREAD_POOL_EXECUTOR。它是一个线程池,代码如下:
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));//根据CPU核心数计算核心线程数
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//根据CPU核心数计算最大线程数
private static final int KEEP_ALIVE_SECONDS = 30;
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());
}
};
private static final BlockingQueue sPoolWorkQueue =
new LinkedBlockingQueue(128);//阻塞队列
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
THREAD_POOL_EXECUTOR 指的就是 threadPoolExecutor,它采用的阻塞队列仍旧是LinkedBlockingQueue,容量为128。其核心线程和线程池允许创建的最大线程数都是由CPU的核心数来计算出来的。
如果想要使用并行的线程处理,可以使用如下的代码:
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
也可以传入其他的线程池。
这里顺便提一下cancel方法,代码如下:
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
cancel方法调用了mFuture的cancel方法,其代码如下:
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
U.compareAndSwapInt(this, STATE, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();//中断线程
} finally { // final state
U.putOrderedInt(this, STATE, INTERRUPTED);
}
}
} finally {
finishCompletion();
}
return true;
}
最终调用的是Thread的interrupt()方法。
原理就分析到这里吧。