一句话说透Android里面AsyncTask的源码

91 阅读3分钟

一句话总结:

用餐厅后厨系统类比源码实现:
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());  
        }  
    };  
}  

初始化流程

  1. 创建WorkerRunnable包装任务
  2. FutureTask用于管理任务生命周期
  3. 绑定结果回调方法

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;  
}  

执行流程

  1. 状态机校验(PENDING → RUNNING)
  2. 触发onPreExecute()
  3. 提交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;  
}  

线程切换原理

  1. 后台线程通过Handler发送Message
  2. 主线程Looper处理Message
  3. 反射调用各阶段回调方法

三、设计模式解析

模式源码体现作用
模板方法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);  
}  

五、替代方案对比

特性AsyncTaskKotlin协程WorkManager
线程切换HandlerDispatchers.Main自动生命周期感知
生命周期易泄漏结构化并发系统托管
任务队列固定容量128无限制持久化存储
适用场景简单短任务复杂异步流后台持久任务

AsyncTask源码口诀:
初始化三部曲,Worker封装任务体
线程池分两种,串行并行看需求
Handler做桥梁,主从线程通信息
状态机防错乱,内存泄漏要警惕
新项目换协程,老代码需留意!