一句话总结:
用餐厅后厨系统类比源码实现:
AsyncTask就像一个智能订餐系统,包含接单员、厨师团队和送餐员。以下是核心源码拆解:
一、核心架构组成
1. 三大核心组件
// 源码路径:android/os/AsyncTask.java
public abstract class AsyncTask<Params, Progress, Result> {
// 组件1:Handler(送餐员)
private static InternalHandler sHandler;
// 组件2:线程池(后厨团队)
private static final Executor THREAD_POOL_EXECUTOR;
// 组件3:任务队列(订单系统)
private final WorkerRunnable<Params, Result> mWorker;
}
二、工作流程源码解析
1. 任务初始化(接单准备)
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
// 关键点:在这里切换到后台线程
return doInBackground(mParams);
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
// 关键点:任务完成回调
postResultIfNotInvoked(get());
}
};
}
初始化流程:
- 创建WorkerRunnable包装任务
- FutureTask用于管理任务生命周期
- 绑定结果回调方法
2. 任务执行(厨房做菜)
// 默认执行入口
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
// 核心执行方法
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) {
if (mStatus != Status.PENDING) {
// 状态校验防止重复执行
switch (mStatus) {
case RUNNING: throw new IllegalStateException("Already running");
case FINISHED: throw new IllegalStateException("Already finished");
}
}
mStatus = Status.RUNNING;
onPreExecute(); // 主线程预处理
mWorker.mParams = params;
exec.execute(mFuture); // 提交到线程池
return this;
}
执行流程:
- 状态机校验(PENDING → RUNNING)
- 触发onPreExecute()
- 提交Future到线程池
3. 线程池核心配置(厨房排班表)
// Android 12源码参数
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;
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE,
KEEP_ALIVE_SECONDS,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(128),
sThreadFactory
);
2025优化点:
- 动态核心线程数(2~4之间)
- 最大线程数基于CPU核心数自动调整
- 队列容量提升至128
4. 结果回调(送餐到桌)
// 内部Handler实现
private static class InternalHandler extends Handler {
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;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result); // 主线程回调
}
mStatus = Status.FINISHED;
}
线程切换原理:
- 后台线程通过Handler发送Message
- 主线程Looper处理Message
- 反射调用各阶段回调方法
三、设计模式解析
| 模式 | 源码体现 | 作用 |
|---|---|---|
| 模板方法 | doInBackground()抽象方法 | 定义算法骨架 |
| 观察者 | 进度更新回调机制 | 状态通知 |
| 工厂 | sThreadFactory | 统一创建线程 |
| 状态机 | mStatus状态管理 | 控制任务生命周期 |
四、源码中的坑与解决方案
坑1:并行执行乱序
源码缺陷:
// 默认串行执行器实现
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> 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();
}
}
问题:队列使用ArrayDeque可能导致任务执行顺序异常
解决方案:
// 改用LinkedBlockingQueue
val safeExecutor = ThreadPoolExecutor(
1, 1, 0L, TimeUnit.MILLISECONDS,
LinkedBlockingQueue<Runnable>()
)
坑2:内存泄漏隐患
危险代码:
// 匿名内部类隐式持有外部类引用
new AsyncTask<Void, Void, Void>() {
protected Void doInBackground(Void... params) {
// 长时间操作
return null;
}
}.execute();
源码修复方案:
// 使用WeakReference包装
public abstract static class WeakAsyncTask<Params, Progress, Result> {
private WeakReference<Context> mContext;
protected WeakAsyncTask(Context context) {
mContext = new WeakReference<>(context);
}
protected abstract Result doInBackground(Params... params);
}
五、替代方案对比
| 特性 | AsyncTask | Kotlin协程 | WorkManager |
|---|---|---|---|
| 线程切换 | Handler | Dispatchers.Main | 自动生命周期感知 |
| 生命周期 | 易泄漏 | 结构化并发 | 系统托管 |
| 任务队列 | 固定容量128 | 无限制 | 持久化存储 |
| 适用场景 | 简单短任务 | 复杂异步流 | 后台持久任务 |
AsyncTask源码口诀:
初始化三部曲,Worker封装任务体
线程池分两种,串行并行看需求
Handler做桥梁,主从线程通信息
状态机防错乱,内存泄漏要警惕
新项目换协程,老代码需留意!