源码解析-AsyncTask源码解析

在之前的博客,我们分析了Handler的源码,在我看来Handler的源码只要理清了流程还是比较简单的。而这次要讲解的AsyncTask的源码我自认为会比Handler稍微复杂一点,我们今天一起来了解一下。


在了解AsyncTask前,你需要先了解以下内容:

1.线程池

2.AsyncTask的基本使用的结构

3.Handler的基本使用


好,我们开始进入正题,还是拿我们之前举的那个例子

AsyncTask task = new AsyncTask<Void, Integer, Void>() {
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
            }
            protected void onProgressUpdate(Integer... values) {
                super.onProgressUpdate(values);
                if (isCancelled()) {
                    return;
                }
            }
 
            @Override
            protected Void doInBackground(Void... voids) {
                publishProgress();
                return null;
            }
 
            @Override
            protected void onPostExecute(Void aVoid) {
                super.onPostExecute(aVoid);
            }
 
            @Override
            protected void onCancelled() {
                super.onCancelled();
            }
        };

        task.execute();

这个是完整AsyncTask的使用的方式,但是实际上在我们创建AsyncTask中只需要重写一个doInBackground方法即可。其他的方法都可以不用重写。那么为什么这样呢?因为AsyncTask是一个抽象类,而他的抽象方法有且只有doInBackground这一个。所以更具抽象类实例化必须要实现他的抽象方法这个规则,所以我们只需要重写一个doInBackground方法。


好了简单的介绍了AsyncTask的使用之后,我们开始进入源码层面剖析AsyncTask。

回想一下,我们使用的AsyncTask的过程只需要创建一个AsyncTask的对象,重写他的子方法,然后启动这个AsyncTask就可以了,那么我们就根据这个流程来分析他的源码。


一、创建AsyncTask

一般我们在创建AsyncTask中使用的是下面的这个方法

    public AsyncTask() {
        this((Looper) null);
    }

而这个方法会调用另外一个构造器

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

首先,这里先根据传入的 Looper 来创建一个Handler,这个mHandler在AsyncTask中至关重要,AsyncTask要把doinBackground中的执行结果传递给onPostExecute,即从后台运行耗时操作切换到ui线程,都是靠这个mHandler进行的线程的调度。

然后构造器里面又创建了两个对象,mWorker,mFuture。这两个对象也是非常重要的,下面我先简单的介绍一下。

mWorker的类型是WorkerRunnable,这个类很具有迷惑性,但是千万不要把它认作是执行一个后台操作的类,子线程只是调用了他的call方法。这个类的申明是在AsyncTask.java中的,是一个内部静态的抽象类。这个抽象类的构成很简单,我们可以从他的泛型中看出来,他的泛型一个是 mParams,传入之后作为一个变量保存。另一个Result即为call方法的回调,确定参数类型。

再看mFuture,它的类型是FutureTask,进入到这个类的源码,发现这个类实现了RunnableFuture接口。而这个借口又实现了Runnable接口,这个时候我们就知道了,真正执行线程方法的是这个类。这个类把上面的mWorker作为参数传进去了,又规定了一个泛型Result,定义了一个方法done()。

为了更好的理解AsyncTask的完整流程,在这一步中,我们暂时不进行call()与done()方法内容的讲解。至此第一步中的主要操作都在这里完成了。


第二步 实现AsyncTask的子方法

这一步很简单,也没有什么要详细说的。这里主要提一下各个方法,为第三步做铺垫。

AsyncTask可重写的方法 onPreExecute onProgressUpdate doInBackground  onPostExecute  onCancelled。

另外可在AsyncTask还有两个很重要的方法也在这里提一下,一个是 publishProgress(),一个是 cancel()。

具体这些方法是怎么工作的我们将会在第三步重点查看。


第三步 调用方法启动AsyncTask

在日常开发的过程中,我们常用 execute或者executeOnExecutor 来执行AsyncTask,这两个的区别是前者是使用一个叫sDefaultExecutor线程池,而后者用的是我们自定义的线程池

为了方便理解,我们先暂时不对sDefaultExecutor进行讲解,这个线程池我们将会在最后进行讲解

    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        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();

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

        return this;
    }

我们暂时只看executeOnExecutor 方法,这里首先对本次AsyncTask的状态做了判断,根据抛出异常的msg,我们可以得出结论一个AsyncTask只能被启动一次。

接下来AsyncTask把自己的状态设置为正在运行,然后调用了onPreExecute()方法,此时我们的线程还未被切换,所以这里可以做一些线程未被切换的操作(因为一般传入的线程都是UI线程,所以这里的onPreExecute也是在UI线程中,onPreExecute常用于显示提示框之类)

然后程序把传入的参数复制给了mWorker这个对象中,然后调用了传入线程池的execute方法来执行线程(mFuture)。

接下来我们就得到Future这个类里面了,由于他被线程池所执行了,所以这里调用的是他的run方法。具体代码如下

 public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            runner = null;
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

这里的代码也很清晰,首先先进行一次Future状态的判定。然后他会去取他的成员变量callable,这个callable我们可以从Future的构造器中得知就是之前我们在第一步中传入的mWork,他的泛型V就是我们所输出的结果的类型。接下来他就调用了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;
            }

这边我们重点要看的是 result = doInBackground(mParams)  这行代码,这里的mParams就是第三步一开始我们讲的那个 mWorker.mParams = params 赋值而来,而这个doInBackground对应的就是我们必须要重写doInBackground。这里一开始就讲了是启动了一个子线程,对应的doInBackground操作就当然在子线程中完成的了。

我们继续看下去,这边不管是否出错他都调用了postResult这个方法,我们进入到这个方法中看一下

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

可以看出来由于目前在子线程,这边使用了Handler进行线程间消息的通知,这个Handler就是我们第一步中创建的那个。而这个message的obj是创建出来的一个新的对象,这个对象把得到的结果存到了自己变量中。

这里要注意一下,这里涉及到了线程的切换,所以接下来我会分主线程以及线程池中的线程进行讲解

在主线程中

在主线程中,我们需要看一下handler中对应的方法。

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

这边采用了一个私有的内部静态类来申明了这个Handler。我们看一下对应的那个方法,很简单就是result.mTask.finish(result.mData[0]) 这么一行代码,这行代码要对应  Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,new AsyncTaskResult<Result>(this, result)) 一起看。

对应看我们就可以知道这个result.mTask.就是自己,所以我们继续找AsyncTask的finish这个方法。

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

这个方法很简单,先判断isCancelled,如果true,调用onCancelled方法,如果false调用onPostExecute方法,最后把AsyncTask的状态设置成finished。

这里我们关注一下isCancelled方法,他所关联的变量是 mCancelled ,我们看一下这个变量还有在哪里用到的。

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

    public final boolean isCancelled() {
        return mCancelled.get();
    }

    public final boolean cancel(boolean mayInterruptIfRunning) {
        mCancelled.set(true);
        return mFuture.cancel(mayInterruptIfRunning);
    }

从这个几个赋值的地方可以看出来被调用cancel方法和程序异常的时候,isCancelled的值为true。

其实到这里为止我们AsyncTask的流程大体上已经完成了,但是为了严谨我们还是把另外一部分给讲完。

子线程

 public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    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);
        }
    }

回到这里,执行完call方法的之后会调用set(result)方法,然后会执行以下流程

    protected void set(V v) {
        if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
            outcome = v;
            U.putOrderedInt(this, STATE, NORMAL); // final state
            finishCompletion();
        }
    }

private void finishCompletion() {
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {
            if (U.compareAndSwapObject(this, WAITERS, q, null)) {
                for (;;) {
                    Thread t = q.thread;
                    if (t != null) {
                        q.thread = null;
                        LockSupport.unpark(t);
                    }
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    q = next;
                }
                break;
            }
        }

        done();

        callable = null;        // to reduce footprint
    }

这两个方法最后调用done(),这个done方法对应的就是我们在初始化的时候创建的mFuture里面的done,代码如下

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

    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

乍一看代码,这里又postResult一遍,但是由于之前call方法中第一行就把这个值设成true,所以这个方法最后是不执行的。

讲到这里基本上已经把大部分的AsyncTask的流程都讲完了,接下来要讲的是 publishProgress 这个方法,让我们看一下源码

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

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

还是想handler发送了一条消息,然后handler取出他的mDate,也就是之前传入的values,调用AsyncTask的onProgressUpdate方法,这样publishProgress也就讲完了,那么整个AsyncTask的流程就讲完了。

写到这里感觉这篇文章有点过长了,太长的文章不仅作者写起来费劲,读者读起来也费尽。那么AsyncTask的总结与自身的默认线程池将放在下一篇博客中讲解=。=

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值