Android中AsyncTask源码详解

AsyncTask类结构分析

public abstract class AsyncTask<Params, Progress, Result> {
    // 下面几个都是new线程池的一些参数,就不具体解释了
    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());
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    // 这个线程池是负责管理任务执行的。注意,是static修饰的,整个应用的所有AsyncTask共用
    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;
    }

    // 任务执行中、执行完成,通过handler通知主线程
    private static InternalHandler sHandler;
    private static final int MESSAGE_POST_RESULT = 0x1;
    private static final int MESSAGE_POST_PROGRESS = 0x2;

    // 这个是存储任务的线程池,也是static修饰的,所有AsyncTask共用这一个线程池存储任务
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

    // 这个是负责执行结果回调的Callback对象(并没有继承Runnable)
    private final WorkerRunnable<Params, Result> mWorker;

    // 这个继承Runnable,负责把doInBackground()方法中的耗时逻辑集成到Runnable中,才能作为参数传给线程池
    private final FutureTask<Result> mFuture;
    ......
    ......
    ......
}

这个类里有两个线程池,都是static的,全局共享,一个负责存储Runnable对象,一个负责执行任务,为了方便后面描述,我们分别命名为“存储线程池”和“执行线程池”。

但是线程池只接收Runnable参数,所以需要一个Runnable对象把doInBackground()方法中的代码集成进去,这样才能被线程池接收。如何集成?就是在run()方法中调用耗时操作,但是问题又来了,如果把执行结果返回回去呢?

所以又需要WorkerRunnable对象,将耗时操作和执行结果返回封装一下,在run()方法中调用WorkerRunnable的call()方法。


再看构造方法:

public AsyncTask() {
    // 初始化WorkerRunnable对象,封装耗时操作和执行结果
    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            mTaskInvoked.set(true);
            Result result = null;
            try {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                // 执行耗时操作
                result = doInBackground(mParams);
                Binder.flushPendingCommands();
            } catch (Throwable tr) {
                 mCancelled.set(true);
                throw tr;
            } finally {
                // 通知掉用处,返回结果
                postResult(result);
            }
            return result;
        }
    };

    // 初始化Runnable对象,与WorkerRunnable绑定,线程池中调用Runnable的run()方法时,就会调用WorkerRunnable的call()方法
    mFuture = new FutureTask<Result>(mWorker) {
        @Override
        protected void done() {
            try {
                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);
            }
        }
    };
}


AsyncTask执行流程分析

AsyncTask有两个重载的execute()方法,一个是默认无参数的,一个是可以自定义Runnable的。先看默认无参数方法:

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    // 将存储线程池作为参数,调用executeOnExecutor()方法
    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("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()方法。这个方法是我们在实现AsyncTask时可以重写的方法,最早执行,用于做一些初始化操作,在UI线程中
    onPreExecute();

    // 将执行参数封装到WorkerRunnable对象中
    mWorker.mParams = params;
    // 调用存储线程池的execute()方法,将FutureTask插入存储线程池中
    exec.execute(mFuture);

    return this;
}

再看有参数、可以自定义Runnable的execute()方法:

public static void execute(Runnable runnable) {
    // 同样,将runnabale插入存储线程池中。跟上面的区别就是,上面插入的Runnable对象是默认的,这里插入的Runnable对象是自定义的
    sDefaultExecutor.execute(runnable);
}


最终都到了存储线程池sDefaultExecutor的execute()方法,我们看一下SerialExecutor类:

private static class SerialExecutor implements Executor {
    // 使用数组队列存储Runnable
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    // 当前正在执行的Runnable
    Runnable mActive;

    public synchronized void execute(final Runnable r) {
        // new要给Runnable,将新任务再次封装一次,插入到队列尾部
        // 由于队列中的任务需要遵循某种逻辑才能依次执行,所以需要重新封装一次
        mTasks.offer(new Runnable() {
            public void run() {
                try {
                    r.run();
                } finally {
                    scheduleNext();
                }
            }
        });

        // 如果当前Runnable为null,说明这是该应用第一次执行AsyncTask,需要执行scheduleNext()方法启动“执行线程池”
        if (mActive == null) {
            scheduleNext();
        }
    }

    protected synchronized void scheduleNext() {
        if ((mActive = mTasks.poll()) != null) {
            // 取出任务,使用执行线程池来执行任务
            THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}

从上面的run()方法可以看出,如果是第一次,就调用scheduleNext()启动任务。如果不是第一次,就把新任务插入到存储线程池中。上一个任务执行完毕后,会调用scheduleNext()方法执行下一个任务。

这里需要注意的是,从doInBackground()到最终启动线程执行耗时操作,中间new了3个Runnable对象。
①第一个Runnable,是为了把doInBackground()中的逻辑代码封装到run()方法中,因为存储线程池SerialExecutor统一接收Runnable对象作为参数;
②第二个Runnable,是为了把耗时操作封装到固定逻辑的run()方法中,这样才能达到依次执行的逻辑;
③第三个Runnable,就是执行线程池中的,真正用来执行耗时操作的,这里会启动n个核心线程和n个非核心线程。
前两个Runnable都是为了代码的可扩展性和灵活性做的管道封装,这两个Runnable都不会调用start()方法启动,只是调用run()方法执行里面的代码而已。

不管怎样,最终都会调用FutureTask的run()方法:

public void run() {
    if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
        return;
    try {
        // 这个callable就是前面mFuture = new FutureTask<Result>(mWorker)中的WorkerRunnable
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                // 调用WorkerRunnable的call()方法
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            if (ran)
                set(result);
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}


在执行线程池中,会在子线程中调用FutureTask的run()方法,而run()方法中又会调用WorkerRunnable的call()方法,所以call()方法是在子线程中调用的:

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

private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    // 通过Handler通知执行结果,这样就可以在主线程中得到执行结果了
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

我们在实现doInBackground()方法时,可以在其中调用publishProgress ()方法通知主线程执行进度:

protected final void publishProgress(Progress... values) {
    if (!isCancelled()) {
        // 同样,也是通过Handler通知执行进度的
        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                new AsyncTaskResult<Progress>(this, values)).sendToTarget();
    }
}

另外,如果我们启动任务时,调用execute(Runnable runnable)方法,使用自定义的Runnable,那最终就只会调用自定义Runnable的run()方法,系统就无法帮我们回调doInbackGround()、postResult()方法,需要我们自己在run()方法中实现耗时操作的处理、结果返回的处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值