AsyncTask原理分析与版本差异

1、概述

AsyncTask是一个轻量级的异步任务类,并可以将结果与执行进度实时传递给主线程,让主线程进行UI更新。

2、相关参数与方法
  • public abstract class AsyncTask。三个泛型参数分别代表了参数值类型,进度类型,返回结果类型。
  • onPreExecute(),在主线程中执行,在异步任务开始之前调用。
  • doInBackground(Params...params),在线程池中执行,用来进行异步任务。
  • publishProgress(Progress... values),可以在doInBackground方法中进行调用来通知主线程中更新进度的方法,来进行进度更新
  • onProgressUpdate(Progress... values) ,主线程中更新进度的方法。用来更新UI中的进度
  • onPostExecute(Result result),当正常完成的时候,调用的方法,此方法也在主线程中执行。
  • onCancelled(),当任务被取消的时候此方法会被调用,onPostExecute方法不会被调用。
3、基本使用
任务所需参数类型为String,进度类型为Integer,返回结果类型为String
    class MyAsyncTask extends AsyncTask{

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            //Todo:做一些准备与初始化操作。
        }

        @Override
        protected String doInBackground(String... strings) {
            //Todo:异步任务

            //Todo:通知进度
            publishProgress(10);

            if (isCancelled()){
                //Todo:判断任务是否被取消掉了,如果被取消掉了,就停止异步任务
                return "";
            }

          //返回结果
            return null;
        }


        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            //Todo:得到进度并更新UI
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            //Todo:任务完成之后会进行调用。如果任务被取消将不会调用此方法。
        }

        @Override
        protected void onCancelled() {
            super.onCancelled();
            //Todo:任务被取消之后会进行调用。
        }
    }
//创建实例对象并使用execute开始任务,参数为处理任务所要参数。
 new MyAsyncTask().execute("www.baidu.com");
4、原理分析
  • 首先我们来看一下AsyncTask的构造方法
    public AsyncTask() {
        this((Looper) null);
    }

    public AsyncTask(@Nullable Handler handler) {
        this(handler != null ? handler.getLooper() : null);
    }


    public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

        mWorker = new WorkerRunnable() {
            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(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);
                }
            }
        };
    }
  • 从27的AsyncTask源码中我们可以看出:第一步:AsyncTask有三个构造方法,最终都会调用AsyncTask(@Nullable Looper callbackLooper)这个构造方法,首先AsyncTask会初始化一个Handler用来处理消息,而默认情况下,会拿我们主线程的looper构建我们的Handler,所以我们所有的消息处理都是在主线程当中的。
  • 第二部,AysncTask将我们参数与返回值封装成一个WorkerRunnable对象,又将WorkerRunnable封装为FutureTask(执行在线程中的Runnable),FutureTask中的run方法会调用WorkerRunnable的Call方法,在任务执行的时候(在线程池中被子线程)被调用,mTaskInvoked会设置为true表示任务已经执行,然后调用doInBackgroud方法传入参数并返回result结果,并最终调用postResult返回结果。
    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult(this, result));
        message.sendToTarget();
        return result;
    }

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

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

通过pstResult的源码我们可以看出。使用了Handler发送了一个消息,而我们的Handler在默认构造的时候是InternalHandler 。可以看到处理MESSAGE_POST_RESULT的时候调用的finish方法,判断是否是被取消,如果被取消就调用onCancelled方法,如果没有被取消调用onPostExecute方法, 所以onCancellde和onPostExecute方法都是在主线程中执行的。

  • 接下来我们来分析任务是怎么异步进行的。我们从execute方法来分析。
   public final AsyncTask execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
    public final AsyncTask 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;
    }

execute方法调用了executeOnExecutor方法。在这个方法中我们可以看到首先调用onPreExecute()方法;此方法会在AsyncTask.execute方法调用的线程中执行。最先执行的方法。然后调用exec.execute(mFuture)方法,exec是一个SerialExecutor对象

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

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
    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;
    }

从它的源码中我们可以看出,他是一个线程池。但是他里面只有一个存放任务的ArrayDeque队列。在execute方法中用offer方法把任务加到队列当中,如果没有任务在执行的话就调用scheduleNext方法执行任务,而当任务完成之后如果还有任务,还会调用这个方法继续执行,从这里我们可以看出AsyncTask方法是串行执行任务的。我们在scheduleNext方法中可以看到其调用了THREAD_POOL_EXECUTOR的execute方法执行任务,而THREAD_POOL_EXECUTOR是一个线程池。所以这里才是真正执行任务的线程池。
对于publishProgress和onProgressUpdate这两个方法的源码大家可以自己看一下,只是用了handler将消息发送到主线程而已,源码比较简单。

5、各版本中的差异

在Android1.6之前AsyncTask是串行执行任务的,在1.6的时候修改成了线程池并行处理任务,但是从3.0开始,为了避免并发错误,又改为用一个线程串行执行任务,但是保留了executeOnExecutor方法来并行的执行任务,参数为THREAD_POOL_EXECUTOR。

你可能感兴趣的:(AsyncTask原理分析与版本差异)