从0开始学安卓源码分析--AsyncTask源码

2019-01-23  本文已影响24人  花生壳_9048

问题:

  1. 为什么一个AsyncTask只能被执行一次?
  2. 为什么AsyncTask是串行执行的, 不能并行吗?
  3. 为什么AsyncTask必须在UI线程中创建?

带着问题看源码, 稳.

看一个源码当然从其构造函数出发.

public AsyncTask(@Nullable Looper callbackLooper) {
        // 这里是为什么需要在主线程创建的原因, 不然怎么去更新ui?
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);
        // WorkerRunnable实现callable接口并实现了它的call()方法
        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;
            }
        };

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

在这个构造方法里可以看到doInBackground(mParams) 方法, 也就是我们继承AsyncTask 复写的方法. 该方法返回了result结果, 最终在finally里调用postResult(result); 将结果通过handler传递进行处理. 在handler的handleMessage中会调用AsyncTask的finish()方法.

private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

这里就找到了 onPostExecute(result); 将结果通过onPostExecute回调到上层了.

FutureTask是一个可管理的任务类, 它实现了Runnable和Callable两个接口, 稍微瞄一眼源码可知其可以对Runnable和Callable进行包装.
这里将WorkerRunnable作为入参传递给了FutureTask.
AsyncTask还并未开始执行, 真正执行需要调用AsyncTask.execute(params);, 并将params传递进去.

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

接着看executeOnExecutor(sDefaultExecutor, params);

这里需要看下AsyncTask的三个状态:

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        // 这里也是为什么一个AsyncTask只能执行一次的原因
        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进行一些不耗时初始化的操作
        onPreExecute();

        mWorker.mParams = params;
        // 这里开始真正执行task任务
        exec.execute(mFuture);

        return this;
    }

调用exec.execute(mFuture);真正执行任务的exec是什么呢?
是传递进来的sDefaultExecutor .

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

private static class SerialExecutor implements Executor {
        // ArrayDeque 先进先出的双端队列
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            // 先将任务都存入队列里
            // 当前没有执行的任务则从队列中取出一个用THREAD_POOL_EXECUTOR执行.
            // 当前有执行的任务则是在任务完成后的finally里取出一个执行
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

sDefaultExecutor是一个静态的串行执行器, 也就是如果都调用AsyncTask.execute(params);方法, 那么一个进程内所有AsyncTask都是由sDefaultExecutor 串行执行的. 这样保证一个时间只有一个任务执行.
如果需要并行执行任务则需要调用executeOnExecutor(Executor exec,Params... params)

另外注意再看看THREAD_POOL_EXECUTOR

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

线程池用到了一个容量128的阻塞队列.

到这里我们继承AsyncTask需要复写的方法,就都已经在流程中出现了

还有另外一个onProgressUpdate(progress) 在哪儿呢?
搜索一下源码.

protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }

可以在doInBackground()中调用publishProgress()方法来进行进度的更新. 通过handler来将更新进度发布到UI线程并回调onProgressUpdate(progress)方法

AsyncTask的源码到这里已经分析完了, 总的来说难度不大. 最后AsyncTask可能会导致内存泄漏, 记得适时的调用AsyncTask的cancel()方法

上一篇下一篇

猜你喜欢

热点阅读