AsyncTask源码解析

AsyncTask是用来在实现在子线程执行任务后切换到UI线程,常见的比如下载任务的更新,执行下载后在UI线程实时更新进度条。由于是基本的API所以还是很有必要了解源码的。

使用

使用其实也很简单,主要是实现AsyncTask类,然后执行excute方法。其中有3个参数和4个方法是必须要掌握的。

  private class MyAsyncTask extends AsyncTask<String, String, String> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
        }

        @Override
        protected void onProgressUpdate(String... values) {
            super.onProgressUpdate(values);
        }

        @Override
        protected String doInBackground(String... strings) {
            return null;
        }
    }

onPreExecute

这个方法是在UI线程执行,并且在后台任务开始前执行。

doInBackground

这个在线程执行,这里主要是做耗时任务。这个方法有参数和返回值,参数就是在调用execute传进来的参数,返回值就是我们经过一些列操作后返回给onProgressUpdate方法的,主要用于UI的更新。例如我下载到50%然后同志UI实时更新。

onProgressUpdate

从方法名看就是更新进度,这个参数就是doInBackground中返回的。

onPostExecute

这个方法就是任务执行完成后要执行的方法。参数也是执行的结果。

三个参数

掌握了这4个方法,这三个参数就很容易理解了。

第一个,是传入的参数。

第二个,是执行任务时进度更新的值。

第三个,任务执行结束的返回值。

源码

其实源码无非就是看内部的核心机制,和这几个方法的调用流程。最直观的就从execute方法开始。

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

这里直接调用了executeOnExecutor,传入了sDefaultExecutor和参数。

 @MainThread
    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();

        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }

先看下这个函数里面都做了什么,在分析sDefaultExecutor。executeOnExecutor这个函数是public的所以我们也可以直接通过这个函数执行任务。如果我们通过executeOnExecutor()这个方法的话就要自己创建一个Executor,因为默认的Executor是使用队列维护同时只有一个线程执行任务,多任务时会被添加到队列中,后面会讲到。

首先,进来先判断状态,如果如果不是没执行过的要抛出异常,这就是为什么如果执行两次任务会报java.lang.IllegalStateException这个错的原因。

其次,将状态改为正在执行。

然后,执行onPreExecute()方法,这就是为什么这个方法在主线程,而且在任务前执行。

再然后开始执行Executor的任务,这时候我们可以分析sDefaultExecutor了。

类里可以看到

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

这两个常量其实就是默认创建了一个Executor


    private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        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();
            }
        }

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

这个SerialExecutor里面维护了一个队列,然后通过offer()在队列的末尾加入任务,通过poll()在头部检索出任务并删除,检索后赋值给mActive。因为首次mActive为null,所以加入了判断mActive==null的时候执行scheduleNext(),后面再有任务来的话mActive就不是null了,所以是在runable中,通过finally调用了scheduleNext(),这时候就会等任务执行完成后在执行下一个任务。这就是上面说的为什么默认的SerialExecutor只能同时在一个线程执行任务。

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    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;
    }

这个主要就是通过各种默认为的参数创建了一个线程池去执行任务。

这就是主要流程,但是在这个流程中还忽略了很多内容,在我们了解了整体框架流程后,在去填充我们想知道的细节,就更容易理解了。

首先看executeOnExecutor()方法中有两个很重要的内容一个是mWorker和mFuture。其实执行任务的时候传入了mFuture,而mFuture是一个mFutureTask真正执行的是mWorker。

     /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        this((Looper) null);
    }

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     *
     * @hide
     */
    public AsyncTask(@Nullable Handler handler) {
        this(handler != null ? handler.getLooper() : null);
    }

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     *
     * @hide
     */
    public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

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

在构造里创建了三部分内容,mHandler、mWorker、mFutur

可以看到首先会创建handler因为,线程通信还是需要依靠Handler。然后mWorker中主要就是执行doInBackground()然后将result传给postResult。

private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

  

postResult主要就是通过handler发送一个what为MESSAGE_POST_RESULT,obj为result的message。

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

这时候看handleMessage是怎么处理的。
这里主要是调用区分what是完成还是未完成完成的话就是调用finish方法,未完成就是onProgressUpdate方法,

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

在看finish方法就是判断是否取消然后调用onPostExecut方法将结果传入。
hadlerMessage还处理一个就是更新进度,那这个message是在哪里发的呢?

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

可以看到是通过publishProgress这个方法,所以我们如果需要更新进度的话要自己在doInBackground这个方法里调用publishProgress()方法传入进度。然后在才会在onProgressUpdate()这个方法中收到。

总结

至此 整个流程也就清晰了,这四个方法是分别在哪里调用的在能实现异步然后更新UI的功能,其实原理很简单,就是用了一个线城池然后我们在子线程实时通过Handler发送Message到UI线程中执行进度的任务,默认通过一个队列维护任务,也可以自定义Executor来实现多线程执行任务。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值