是什么东西?
顾名思义,异步任务,就是说我们可以让我们异步执行任务,不过通常使用它是为了异步执行,主线程更新UI,我们都知道,Android 的UI更新操作,都会检查是否是主线程,如果不是的话就会报出异常,这一步是在ViewRootImpl里面做的,这里就不多说了。在使用的时候,我们只需要将后台处理的代码写在doInBackground,更新UI的工作写在onPostExecute就行了,就可以轻松实现一个线程切换,更新UI的效果。那这里你可能会问。为什么不用Handler,我也许会告诉你,使用 AsyncTask 有很多好处,待会会慢慢告诉你,你也可以根据源码,一探究竟。
前世今生
没有继承自任何东西,Object 除外,使用了模板定义,Params 代表你要传的参数类型,Progress 代表更新数据类型,Result 是任务执行玩返回数据类型。
public abstract class AsyncTask {}
使用场景
只要需要开启子线程的都可以使用它。在项目中,随便 new Thread 并不是一个好习惯,滥用不说,很有可能造成内存泄露
实现原理大白话
有两个东西很关键,一个是线程池,一个是 Handler,线程池负责执行任务, Handler 负责通知,说道这,聪明的你大概猜到了实现方式,但这并不够,我们需要细细的品味这个类是如何写成的。
源码解析
属性
通过使用 Runtime 对象获取可用的cpu 个数,在创建线程池时创建合适的线程数量,线程池的参数主要是核心线程数,这里最小值2, 最大值4,当处理器个数为4时,创建3个核心线程数,最大线程数为 cpu个数的两倍 + 1,关于核心线程数,最大线程数,大家可自行去了解作用,以后创建线程池,大家可要记住了,以这样创建线程池数是比较合理的。KeepAliveTime 是线程存活时间,超过这个时间的线程要被回收,至于哪一些线程,待会再说
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));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;
静态线程工厂,在类加载是就会被创建,里面使用了AtomicInteger 用来计数。使用了LinkedBlockingQueue作为任务队列
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;
使用静态代码块初始化线程池,参数为以上分析的数据,注意,allowCoreThreadTimeOut 设置为true,意思是允许核心线程数被回收,默认是不会被回收的
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;
}
还有一个重头戏,单任务执行器,默认不是用上面的线程池执行任务,而是使用序列执行器执行任务,意识就是,同一时刻只能执行一个任务,注意这些都是静态的,也就是说,一个进程,不管你新建了多少个 Task对象,他也只能单个任务执行,这样就很好的管理了资源,那他是如何做到单任务执行的呢,实现方式可以说是既巧妙又无语,且看注释
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static class SerialExecutor implements Executor {
// 保存任务
final ArrayDeque mTasks = new ArrayDeque();
Runnable mActive;
public synchronized void execute(final Runnable r) {
// 新任务进来,不执行,而是使用匿名内部类创建一个Task加到任务队列里,
// 当这个执行完的时候,才会去调用下一个任务,就做到了单任务执行。
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
// 默认先
if (mActive == null) {
scheduleNext();
}
}
// 这里是真正去执行的
// 注意,使用到了 synchronized 的可重入特性!
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
一些静态的变量基本看完了,下面来看一下构造函数,有点长
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*
* @hide
*/
public AsyncTask(@Nullable Looper callbackLooper) {
// 首先获取 Handler 对象,这里有主线程 Handler 和子线程Handler 之分
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
// 异步执行的,实现了callable接口
mWorker = new WorkerRunnable() {
public Result call() throws Exception {
// 为了防止多次多次调用实例
mTaskInvoked.set(true);
Result result = null;
try {
// 设置进程的优先级
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// noinspection unchecked
// 在这里执行doInBackground函数,
// 这是我们需要重写的
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
// 执行完,这里还是在子线程
postResult(result);
}
return result;
}
};
// FutureTask 对象,封装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 doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
执行完以后,使用Handler 进行通知,注意,这里将结果装入Message对象中,直接发送。一个小技巧,我们在发送消息是尽可能使用 obtainMessage 获取Message对象要比new一个好得多。
// 返回结果,使用handler
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();
return result;
}
那执行入口呢? MainThread 代表主线程执行
@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;
}
一些我们可能需要实现的函数
// 我们将后台逻辑写在这里
@WorkerThread
protected abstract Result doInBackground(Params... params);
@MainThread
protected void onPreExecute() {
}
// 执行完回调
@MainThread
protected void onPostExecute(Result result) {
}
// 如果有进度条更新
@MainThread
protected void onProgressUpdate(Progress... values) {
}
@MainThread
protected void onCancelled() {
}
如何更新进度条?只需要在 doInBackground 中调用即可,将参数传入,使用handler机制
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult
Handler 处理消息的地方,静态类
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;
}
}
}
当然,你也可以取消任务,不过只能取消还没执行的任务,底层是调用 thread.interrupt 方法,简单粗暴,关于他的使用,可以写一堆东西来说,这里暂且不展开说
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
当然,如果不要于UI交互,你也可以使用这个执行后台逻辑,直接调用executeOnExecutor,使用静态的execute提交,这里是单任务的
public static void execute(Runnable runnable) {
sDefaultExecutor.execute(runnable);
}
当然,也可以多任务一起执行,调用executeOnExecutor时指定内部的线程池即可AsyncTask.THREAD_POOL_EXECUTOR
总结
我们了解这AsyncTask这个类,大致知道了他是怎么实现了,如果要进一步了解的话,线程池,锁这些东西必不可少的~
如有错误,欢迎讨论