AsyncTask源码解析

1.AsyncTask的使用

AsyncTask使用分为三步:

① 创建一个类来继承AsyncTask

②创建一个这个类的实例对象

③使用这个实例对象的execute方法

//第一个,创建一个类继承AsyncTask,记得一定要是静态类,否则会出现内存泄漏

   static class Asyncktask extends AsyncTask{

        @Override
        protected Void doInBackground(Void... voids) {
            return null;
        }
    }
//第一个Void参数类型为Params类型参数,即你传入的参数,第二个参数为Progress类型,即进度的类型
//第三个为Resault类型参数,即返回结果参数类型。
//第二步,创建这个类的实例

    AsyncTask asyncTask = new Asyncktask();

//第三步,调用这个类的execute方法


    asyncTask.execute()

       这是AsyncTask的使用方法,是不是很简单?AsyncTask是用来干嘛的呢?相信能点进来看的各位都知道,但是为了自己记得更牢固一点,还是写一下,因为在主线程中不能干耗时任务,否则会造成ANR(主线程超过5s会出现),因此,一些耗时的操作必须要放到工作线程中去实现,这也就是AsyncTask出现的目的,AsyncTask内部封装了Handler用来切换子线程以及主线程,封装了线程池来进行耗时任务的执行,因此AsyncTask就是为我们封装好的用来执行单个的耗时任务的工具,为什么是单个呢?因为AsyncTask的excute方法只能够执行一次。

       ok,既然知道了它是干嘛的,为了更好的了解它,我们还要知道它是怎么办到的。

       首先我们进入到AsyncTask的构造函数。

//无参构造函数调用了下面的有参构造函数
    public AsyncTask() {
        this((Looper) null);
    }
//这是实际调用的构造函数
    public AsyncTask(@Nullable Looper callbackLooper) {

        //这里把主线程的Handler赋值给AsyncTask的Handler,这样就能够通过
        //这个Handler向主线程发送消息,更新数据。
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

        //这里先不看这个,之后会讲到,这个WorkerRunnable是继承callable接口,作为下面FutureTask的构造参数,之后会执行这个call方法
        mWorker = new WorkerRunnable() {
            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方法
                    postResult(result);
                }
                return result;
            }
        };
         //这个FutureTask实际上是继承了Runnable的,因此可以作为线程池执行的参数去执行
        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);
                }
            }
        };
    }

   第一步,初始化实例对象完成了什么功能呢?首先,它将主线程的Handler赋给了自身的handler,这样就可以切换主线程和子线程,其次,初始化了一个FutureTask对象,它继承了Runnable,这里做了一些封装,将WorkerRunnable对象封装到FutureTask对象中。

之后我们看excute方法,这个方法又做了什么呢?我们点进去来看它的源码。

    //这里标注了必须要在主线程执行
    @MainThread
    public final AsyncTask execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
    
    //调用了executeOnExecutor()方法
        @MainThread
    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;
        //这里就去执行了mFuture这个runnable,会调用exec的execute方法。
        exec.execute(mFuture);

        return this;
    }

         在代码里可以看到,首先判断了是不是运行过,运行过就会把mStaus置为相应的类型(Status枚举类),因此这也就是AsyncTask的execute方法只能运行一次的原因。

         之后会调用第一个回调方法,onPreExecute方法,这也证明了,第一个调用的方法为onPreExecute方法。

         之后会exec的execute方法,这个exec是什么呢?我们看一下。

//exec是一个继承了Executor类型的SerialExecutor类,调用它的execute方法就是调用下面的execute方法

    private static class SerialExecutor implements Executor {
         //这是一个没有容量限制的双向队列
        final ArrayDeque mTasks = new ArrayDeque();
         //mActive是正在执行的Runnable
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            //这里做了一层封装,用new Runnable 封装了传递过来的runnable,也就是我们的
            //FutureTask。
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        //run方法会在线程池中进行
                        r.run();
                    } finally {
                        //进行下面的scheduleNext()方法
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

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

          这个exec是一个继承了Executor的SerialExecutor类。

          在它的execute方法里它主要干了这几件事情:

          ①创建一个队列,装runnable,也就是我们之前提交过来的FutureTask。

          ②用THREAD_POOL_EXECUTOR来处理我们队列里的对象。

          这里注意是run方法执行完毕后才执行scheduleNext方法,因此我们的任务在这里是线性执行的。

         那么下一个问题来了,THREAD_POOL_EXECUTOR又是什么呢?顾名思义,这是一个线程池,设置了一些线程池的参数创建出来的,用来执行我们的FutureTask对象。

        这里就执行了我们的FutureTask对象,还记得我们FutureTask对象里封装了什么吗?对,是一个Callable类型的WorkerRunnable,我们来看源码

    
//我们来看主要的
public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
            //这里的c被赋予了我们传进来的WorkerRunnable对象
            Callable 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方法中调用了Callable也就是我们的WorkerRunnable对象的call方法。

         简洁明了,我们去看这个call方法。

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

           call方法里做了什么呢,

          ①设置了线程池的优先级

          ②调用了第二个回调方法,doInBackground方法,这也就是为什么这个方法是在后台进行的

          ③调用postResault方法,我们点进去看一下

    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")

         //getHandler就会获得我们之前赋值为主线程handler的Handler对象
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult(this, result));
        message.sendToTarget();
        return result;
    }

     做的事情很简单,就是通过主线程的handler把结果发送出去。

     到此,AsycnTask的流程就结束了,还有一些方法没有涉及到,但是都很简单,大家可以去看源码,源码真的很有必要去看,这样能更加深刻的记住它的工作流程。谢谢~

你可能感兴趣的:(AsyncTask源码解析)