流程解读
- 自定义的继承类:因为AsyncTask为抽象类,无法直接创建,必须继承它实现一个子类。
a. 常见的方法
onPreExecute():在执行任务前调用,位于UI线程内
doInBackground():执行任务过程,位于非UI线程内
publishProgress():发布任务进度,一般在doInBackground()中调用,将数据传递给调onPregressUpdate()方法
onPregressUpdate():更新进度条,位于UI线程
onPostExecute():doInBackgound()方法完成后调用,位于UI线程
onCancelled():取消任务,位于UI线程
b. 定义类型
class MyTask extends AsyncTask
Params为传入的数据,比如url;因此,通常设置为String类型;
Progress为更新的进度,通常为Integer类型;
Result为返回的结果,如果我们希望返回一个文件,那么其对应类型为File;
- 创建自定义的MyTask类
MyTask task = new MyTask(...);
创建该类,实际上就会调用AsyncTask的构造函数,如下:
//创建一个异步任务,注意这里必须在UI线程中创建
public AsyncTask(){
//定义任务执行过程,注意这里还没开始执行任务,只是定义任务的执行过程
mWorker = new WorkerRunnable() {
@Override
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//交给子类去实现,获取到结果
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr){
mCancelled.set(true);
throw tr;
} finally {
//最后提交结果
postResult(result);
}
return result;
}
};
//实际上,这里用FutureTask包装Callable的目的是为之后提交给线程池执行,因为线程池并不接收Callable类型
mFuture = new FutureTask(mWorker){
@Override
protected void done() {
try {
//若任务并没有执行过,则需要调用get()方法获取到结果,然后再提交结果
postResultIfNotInvoked(get());
} catch (InterruptedException e){
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e){
throw new RuntimeException("An error occurred while executing doInBackgound", e.getCause());
} catch (CancellationException e){
postResultIfNotInvoked(null);
}
}
};
}
在AsyncTask构造函数内,初始化了两个mWorker
和mFuture
两个变量。我们容易看到其中mFutrue实际上就是一个包装mWorker的FutrueTask实例。
private static abstract class WorkerRunnable implements Callable{
Params[] mParams;
}
如上,实际上WorkerRunnable类型即为Callable类型。
- 执行MyTask实例
mTask.execute(url);
其对应调用AsyncTask中的execute方法,如下:
//外部调用方法,执行任务
public final AsyncTask execute(Params... params){
return executeOnExecutor(sDefaultExecutor, params);
}
//真正执行任务的地方
private 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 benn executed.");
}
}
//标识为正在执行
mStatus = Status.RUNNING;
//执行前调用
onPreExecute();
mWorker.mParams = params;
//执行任务!!!!
exec.execute(mFuture);
return this;
}
首先我们看到executeOnExecutor
中的onPreExecute()
方法,这是任务前执行的方法,然后执行exec.execute(mFuture)
,我们回到mFuture的定义,我们知道mFuture只是mWorker的一层包装,目的是为了交给线程池执行。而mWorkder中会执行result = doInBackground(mParams);
,这个是交给子类去实现,获取到结果。最后再分发结果postResult(result);
。
//获取到Handler对象
private static Handler getHandler(){
synchronized (AsyncTask.class){
if (sHandler == null){
sHandler = new InternalHandler();
}
return sHandler;
}
}
//提交结果
private Result postResult(Result result){
//创建消息
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
//发送消息
message.sendToTarget();
return result;
}
我们可以看到消息将对应的结果通过一个InternalHandler类型来发送
//定义一个UI线程上的Handler对象
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:
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
如上,该类型为UI线程上的一个Handler对象,保证发送的消息可以在UI线程中接收,我们先看到其MESSAGE_POST_RESULT
类型,调用result.mTask.finish(result.mData[0]);
方法
//任务执行完毕,提交结果,并标识
private void finish(Result result){
if (isCancelled()){
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
我们可以看到在finish方法中,调用了onPostExecute(result)
方法将结果发送出去。这样一个完整的流程就结束了。
当然,还有其更新进度方面,我们回到publishProgress()
方法
//更新进度,并发送进度消息
protected final void publishProgress(Progress... values){
if (!isCancelled()){
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult
回到InternalHandler
中,我们可以看到其对应的消息类型,会调用onProgressUpdate()
方法
细节解析
- AsyncTask默认是使用串行执行的方式
//线程执行器,默认为串行执行
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
如何实现串行执行?
添加任务时,将下一个任务添加到上一个任务完成后执行
//实现串行执行
private static class SerialExecutor implements Executor{
//双向队列,存储任务
final ArrayDeque mTasks = new ArrayDeque<>();
//当前正在执行的任务
Runnable mActive;
@Override
public void execute(final Runnable r) {
//添加到队尾
//注意:a. 在这里不是直接传入r,而是重新定义一个runnable,目的在于当前任务执行完后,再从任务队列中获取到下一个,以保证串行
// b. 在这里只是重新定义runnable,并没有开始真正执行!!!
mTasks.offer(new Runnable() {
@Override
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);
}
}
}
- 定义线程池的方法
亮点在于:静态化构造线程池,这样当构建对象时,会初始化线程池
//获取当前CPU核心数
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//定义线程池核心容量
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT-1, 4));
//定义线程池最大容量
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//过剩的空闲线程的存活时间
private static final int KEEP_ALIVE_SECONDS = 30;
//自定义工厂方法,标记线程,以便管理
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
//任务队列
private static final BlockingQueue sPoolWorkQueue = new LinkedBlockingQueue<>(128);
//线程池
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;
}
- 关于不定参数的使用
private static class AsyncTaskResult{
final AsyncTask mTask;
final Data[] mData;
public AsyncTaskResult(AsyncTask mTask, Data... mData) {
this.mTask = mTask;
this.mData = mData;
}
}
使用不定参数的目的在于在构造这样的类时,传入的Data数据类型可变:
private Result postResult(Result result){
//创建消息
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
}
protected final void publishProgress(Progress... values){
if (!isCancelled()){
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult