0、目录
一、简介
二、使用方法以可能存在的问题
三、工作原理
四、类和核心方法的介绍
4.1、类定义
2.2、核心方法
五、源码分析
六、总结
一、简介
二、使用方法以及可能存在的问题
使用方法请详见《AsyncTask使用详细介绍(含使用实例)》
可能存在的问题详见《AsyncTask存在的问题和缺陷》
三、工作原理
AsyncTask的实现原理:线程池+Handler
1、内部实现创建工作线程,并使用线程池实现线程的调度和复用
2、内部实现Handler用于异步通信,实现更新UI
因为,每次使用时,无论创建工作线程,还是实现异步通信,都是固定的模式,且都要实现一遍,显然是很麻烦的,所以系统内部抽象出了AsyncTask类,使我们不用再关注创建工作线程和异步通信,而是重点关注业务的实现。
内部实现了两个线程池和一个Handler.
四、类和核心方法的介绍
4.1、类定义
public abstract class AsyncTask<Params, Progress, Result> {
......
}
1、首先AsyncTask是抽象类,所以不可直接实例化,必须实现子类。
2、 AsyncTask<Params, Progress, Result>使用泛型,主要作用是在执行任务控制输入或返回的数据类型。
Params:决定了执行excute()方法时传入的参数类型,excute()方法传入的参数会传入到方法doInBackground(),所以同时也决定了doInBackground()方法内的参数类型。
Progress:任务执行时,返回进度值的类型,即onProgressUpdate()方法内的参数类型。
Result:任务完成后,返回的结果的类型,即doInBackground()方法的返回类型,doInBackground()方法的返回结果传入onPostExecute()方法作为参数,所以同时也决定了onPostExecute()方法的参数类型。
注:Params, Progress, Result并不一定都要使用,如果没有使用,可以用java.lang.Void代替。
2.2、核心方法
切记自己不能手动调用onPreExecute(), doInBackground(), onProgressUpdate(),onPostExecute(),onCancelled()等方法,这些方法都是系统自动调用的。
五、源码分析
AsyncTask的使用可以分为三步:
步骤一:继承AsyncTask,创建AsyncTask的子类,并根据需要复写相关方法
步骤二:创建AsyncTask子类的实例对象
步骤三:调用该子类实例对象的execute()方法,执行异步任务
具体如下:
//步骤1、创建AsyncTask的子类,并根据需要复写相关方法
//继承AsyncTask,并确定泛型类型
class mAsyncTask extends AsyncTask<String, Integer, String> {
//UI线程执行
//任务执行前的准备工作
@Override
protected void onPreExecute() {
}
//必须复写,因其在AsyncTask内是抽象函数
//异步任务真正执行的位置
@Override
protected String doInBackground(String... strings) {
//子线程中执行
//可调用publidshProgress(Integer)方法触发onProgressUpdate()方法执行,更新进度
return null;
}
//UI线程执行
//更新线程任务进度
@Override
protected void onProgressUpdate(Integer... values) {
}
//UI线程执行
//异步任务执行完成后的一些操作
@Override
protected void onPostExecute(String s) {
}
//UI线程执行
//异步任务被取消时调用
@Override
protected void onCancelled(String s) {
}
}
//步骤2、创建AsyncTask的子类实例对象
//UI线程中执行
mAsyncTask task = new mAsyncTask();
//步骤3、调用子类实例对象的execute()方法,执行异步任务
//UI线程中手动调用execute(Params... params)方法,系统会自动调用步骤一中的各种方法
//同一个实例对象只能执行一次,否则会抛出异常
task.execute();
接下来,根据具体使用过程中的三个步骤,分别依次分析源码
步骤一:继承AsyncTask,创建AsyncTask的子类,并根据需要复写相关方法
复写的方法将会在后面调用
步骤2、创建AsyncTask的子类实例对象
mAsyncTask task = new mAsyncTask();
//构造函数
public AsyncTask() {
//即调用 AsyncTask(Looper callbackLooper)
this((Looper) null);
}
public AsyncTask(@Nullable Looper callbackLooper) {
//1、判断参数callbackLooper是否为空或为主线程的Looper,
//若是则获取主线程Handler,否则根据callbackLooper创建新的Handler
//getMainHandler() -->>分析1
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
//2、初始化一个WorkerRunnable -->>分析5
mWorker = new WorkerRunnable<Params, Result>() {
//实现了call()方法,在调用execute()方法时调用
//类似于Runnable中的run()方法,
public Result call() throws Exception {
//已经在工作线程中执行
//添加线程任务的一个标志
mTaskInvoked.set(true);
Result result = null;
try {
//设置线程优先级
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//调用步骤一中复写的doInBackground()方法,即执行的异步耗时操作
//mParams是在执行execute()方法时传入的参数
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
//最后把异步任务执行的结果传到主线程,更新UI -->>分析6
postResult(result);
}
return result;
}
};
//创建一个FutureTask,来执行mWorker -->>分析7
mFuture = new FutureTask<Result>(mWorker) {
//invoked when this task transitions to state isDone (whether normally or via cancellation)
//当FutureTask内的(mWorker内的)Callable被执行完成后被调用
//作用是检查任务的调用,将未被调用的任务的结果传递到主线程
@Override
protected void done() {
try {
//-->>分析8
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);
}
}
};
}
分析1:getMainHandler()
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
//如果sHandler为空,则根据主线程的Looper创建一个InternalHandler对象实例
//即InternalHandler类型的sHandler绑定到了主线程的Looper -->>分析2
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
//分析2:InternalHandler
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
//复写handleMessage()
//已经是在UI线程执行
@Override
public void handleMessage(Message msg) {
//传过来的Message的obj对象是AsyncTaskResult<?>类型
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
//MESSAGE_POST_RESULT表示传递过来的是resulet
//数据是在postResult(Result result)方法内传递过来的
case MESSAGE_POST_RESULT:
// 如果传递来的是结果 -->>分析3
result.mTask.finish(result.mData[0]);
break;
//MESSAGE_POST_PROGRESS表示传递过来的数据是执行任务的进度值
//数据在publishProgress(Progress... values)方法内传递过来的
case MESSAGE_POST_PROGRESS:
// 如果传递来的是执行任务的进度值 -->>分析4
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
分析3:result.mTask.finish(result.mData[0]);
result 是AsyncTaskResult<?> 类型的,定义如下:
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
result.mTask是AsyncTask 类型的,其finish()方法定义如下:
private void finish(Result result) {
//isCancelled():Returns true if this task was cancelled before it completed normally
if (isCancelled()) {
//执行异步任务过程中点击取消,则调用步骤一中复写的onCancelled()方法
onCancelled(result);
} else {
//否则调用步骤一中复写的onPostExecute()方法
onPostExecute(result);
}
//状态标记为完成
mStatus = Status.FINISHED;
}
分析4:result.mTask.onProgressUpdate(result.mData);
即调用步骤一中复写的onProgressUpdate()方法
分析5:WorkerRunnable
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
抽象类WorkerRunnable继承了Callable,且有一变量mParams,该变量在调用execute()方法时用于表示传入的参数。
分析6:postResult(result)
private Result postResult(Result result) {
//getHandler即是分析1中返回的sHandler
//obtainMessage (int what, Object obj),即what是MESSAGE_POST_RESULT;
//obj是new AsyncTaskResult<Result>(this, result)
//obtainMessage ()中,还把getHandler()中获得的sHandler赋制给了Message的Target属性
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
//即把Message对象发给了getHandler()中获得的sHandler,之后由分析3处理
message.sendToTarget();
return result;
}
分析7:FutureTask
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
callable类似于Runnable,执行FutureTask的对象实例时,callable内的call()方法将被执行
分析8:postResultIfNotInvoked
private void postResultIfNotInvoked(Result result) {
//获得线程的状态
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
//传递结果到主线程,详见分析6
postResult(result);
}
}
总结:
1、获得InternalHandler 类型的Handler,用于异步消息的处理
2、创建了一个WorkerRunnable类实例对象mWork,并复写了call()方法,call()方法内的代码已经是在工作线程中执行
3、创建了一个FutureTask类实例对象mFuture,并复写了done()方法
4、通过分析可以看到,在步骤一中复写的一些方法已经被使用
步骤3、调用子类实例对象的execute()方法,执行异步任务
执行代码:
task.execute();
//源码分析:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
//sDefaultExecutor是一个SerialExecutor类型线程池 -->>分析1
//executeOnExecutor() -->>分析4
return executeOnExecutor(sDefaultExecutor, params);
}
分析1:线程池SerialExecutor
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
线程池SerialExecutor源码如下:
private static class SerialExecutor implements Executor {
//static :说明这是一个静态内部类
//存放Runnable类型元素的双向队列
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
//该方法被synchronized关键字修饰
//表示多个线程同时执行时只有一个线程能进入该方法
//具体调用位置是在executeOnExecutor()方法内的exec.execute(mFuture)
//mFuture-->mWorker-->call()
public synchronized void execute(final Runnable r) {
//把Runnable类对象添加到mTasks队列
//把异步任务和取出下一个任务并执行作为一个Runnable对象放到队列mTasks
//目的是为了一个任务执行完成后,能自动执行下一个任务
//从这里能够看出异步任务的执行时串行的,即执行完一个任务后再执行下一个任务
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
//执行完一个异步任务后自动从队列取出下一个任务并执行 -->>分析2
scheduleNext();
}
}
});
//添加队列后,判断当前是否有任务正在执行,若没有,从队列取出任务并执行
//一般在添加第一个任务到队列时使用,即添加第一个任务后,取出第一个任务并执行
if (mActive == null) {
scheduleNext();
}
}
//从mTasks队列取出下一个任务并执行
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
分析2:scheduleNext()
//从队列中取出一个任务并执行
protected synchronized void scheduleNext() {
//从队列mTasks中取出一个任务
if ((mActive = mTasks.poll()) != null) {
//调用线程池THREAD_POOL_EXECUTOR执行该任务
// -->>分析3
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
分析3:线程池THREAD_POOL_EXECUTOR相关的源码
//CPU的数量 Returns the number of processors available to the JVM.
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//线程池的核心线程数量,数量在2--4之间
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);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
//创建存放Runnable类型的任务队列,且最多存放128个
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(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;
}
通过线程池THREAD_POOL_EXECUTOR 的创建,可以看到它是可以并行执行的,只是在实际使用中,执行完一个异步任务后再取出下一个交由线程池THREAD_POOL_EXECUTOR 去处理,所以最后任务的执行依然是串行的。
分析4: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()
onPreExecute();
//execute()传入的参数赋值,以便在mWorker中使用
mWorker.mParams = params;
//执行异步任务 exec就是线程池SerialExecutor的实例对象,详见分析1
exec.execute(mFuture);
return this;
}
总结:
1、异步任务执行时,通过SerialExecutor类型线程池把所有的线程顺序放到一个队列中
2、然后再从这个队列中取出任务,由线程池THREAD_POOL_EXECUTOR执行异步任务,执行完一个任务后再从队列中取出下一个任务并执行,任务是串行执行的。
如想异步任务并行执行,在主线程调用AsyncTask的executeOnExecutor (Executor exec, Params... params)方法,其中第一个参数为AsyncTask.THREAD_POOL_EXECUTOR。
取消异步线程任务
执行:task.cancel(true);
//源码:
//即便是取消任务,实际并没有真正取消,异步任务依然会执行,直到结束
//只是任务结束后,不会再调用onPostExecute()方法,而是调用onCancelled()方法
public final boolean cancel(boolean mayInterruptIfRunning) {
//设置任务是否被取消标志
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
六、总结
最后做一个简单的总结: