AsyncTask源码解析

在Ui线程需要与子线程进行数据交互,并涉及到UI更新的时AsyncTask是最常用的办法。所以作为Android开发中最容易用到的一个类,非常有必要研习一下他的源码。这样将有助于更灵活的在应用层使用这个类。

AsyncTask常用方式举例

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {

      /**
     * Runs on the UI thread before {@link #doInBackground}.
     *
     * @see #onPostExecute
     * @see #doInBackground
     */
      @MainThread
      protected onPreExecute() {
      }

      /**
     * Override this method to perform a computation on a background thread. The
     * specified parameters are the parameters passed to {@link #execute}
     * by the caller of this task.
     *
     * This method can call {@link #publishProgress} to publish updates
     * on the UI thread.
     *
     * @param params The parameters of the task.
     *
     * @return A result, defined by the subclass of this task.
     *
     * @see #onPreExecute()
     * @see #onPostExecute
     * @see #publishProgress
     */
    @WorkerThread
    protected Long doInBackground(URL... urls) {
          int count = urls.length;
          long totalSize = 0;
          for (int i = 0; i < count; i++) {
              totalSize += Downloader.downloadFile(urls[i]);
              publishProgress((int) ((i / (float) count) * 100));
              // Escape early if cancel() is called
              if (isCancelled()) break;
          }
          return totalSize;
    }


      /**
     * Runs on the UI thread after {@link #publishProgress} is invoked.
     * The specified values are the values passed to {@link #publishProgress}.
     *
     * @param values The values indicating progress.
     *
     * @see #publishProgress
     * @see #doInBackground
     */
    @SuppressWarnings({"UnusedDeclaration"})
    @MainThread
    protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
    }

     /**
     * <p>Runs on the UI thread after {@link #doInBackground}. The
     * specified result is the value returned by {@link #doInBackground}.</p>
     * 
     * <p>This method won't be invoked if the task was cancelled.</p>
     *
     * @param result The result of the operation computed by {@link #doInBackground}.
     *
     * @see #onPreExecute
     * @see #doInBackground
     * @see #onCancelled(Object) 
     */
    @SuppressWarnings({"UnusedDeclaration"})
    @MainThread
    protected void onPostExecute(Long result) {
          showDialog("Downloaded " + result + " bytes");
    }
  }

我是非常强调看源码注释的。尤其是分析源码方法的时候。一个良好的代码,注释能快速让人了解他的用途。并理解这段代码的意义和目的。
上面这个example来自AsyncTask.java的类注释。为了充分说明AsyncTask我给他额外添加了经常用到的onPreExecute。
官方注释的example我给他还额外添加了每个方法的注释。注释已经明白的讲明了以上几个方法的作用及意义。这里归纳一下:

AsyncTask<URL, Integer, Long>

我们一般在使用AsyncTask的时候都是会继承于他的.并且用泛型来做出一定的限制.
第一个参数是后台线程入口需要的参数,这里是在模拟下载的过程,所以后台线程需要的url是要作为泛型进行限制的.
第二个参数是在有进度条的情境下使用的.这个泛型限制是表示进度条每一个进度的单位类型.一般进度条使用Integer做进度展现即可.
第三个参数是当后台线程执行完之后返回给UI线程的Result的类型.
这三个参数都是选填的.如果都不需要那么均置为VOID即可.

/**
     * Runs on the UI thread before {@link #doInBackground}.
     *
     * @see #onPostExecute
     * @see #doInBackground
     */
      @MainThread
      protected onPreExecute() {
      }

这个方法跑在UI线程,这个方法主要是做一下预先的设置工作.这里其实@MainThread就是表示了这个方法跑在UI线程的.

  /**
     * Override this method to perform a computation on a background thread. The
     * specified parameters are the parameters passed to {@link #execute}
     * by the caller of this task.
     *
     * This method can call {@link #publishProgress} to publish updates
     * on the UI thread.
     *
     * @param params The parameters of the task.
     *
     * @return A result, defined by the subclass of this task.
     *
     * @see #onPreExecute()
     * @see #onPostExecute
     * @see #publishProgress
     */
    @WorkerThread
    protected Long doInBackground(URL... urls) {

在做了必须的一些设置之后,AsyncTask的protected Long doInBackground(URL... urls)会被调用.这个是跑在子线程的.所以耗时的任务是在这里写的.这里的...表示方法的参数可以使一个及以上的.
有时候你在下载的时候要展现一点一点下载的过程,那就需要在执行耗时任务的同时告诉UI去更新.那就需要publishProgress()出马了.他会在自己每次被调用的时候都去通知AsyncTask的onProgressUpdate:

 /**
     * Runs on the UI thread after {@link #publishProgress} is invoked.
     * The specified values are the values passed to {@link #publishProgress}.
     *
     * @param values The values indicating progress.
     *
     * @see #publishProgress
     * @see #doInBackground
     */
    @SuppressWarnings({"UnusedDeclaration"})
    @MainThread
    protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
    }

看,注释就是这样的意思:只要publishProgress被调用,那onProgressUpdate就会执行.是不是用起来很爽?
当完成了protected Long doInBackground(URL... urls)的操作之后,protected void onPostExecute(Long result) {就会执行.
当使用的时候就可以直接在UI线程调用:

new DownloadFilesTask().execute(url1, url2, url3);

即可

AsyncTask源码分析

new出一个AsyncTask对象

AsyncTask源码分析的入口点就是在UI线程中调用的代码.
首先我们会new出一个AsyncTask对象.看一下这个动作会做什么事情:

public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }
        };

        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 occured while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }

这里看似代码很长,有用的也就两个成员变量:mWorker mFuture
不妨看一下这两个对象是个什么:找到他们的继承关系:
这里写图片描述

这里写图片描述
而RunnableFuture接口是继承自Runnable接口的,所以mFuture就是一个Runnable接口
所以就有必要进入FutureTask的run方法看一下:

public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();//这一行回调的事mWorker的call方法
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);//这一行最终调用的是mFuture的done方法
            }
        } 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);
        }
    }

这一切就是两行注释所做的事情.那么他们什么时候真正的执行起来的呢?就是在AsyncTask执行execute动作的时候

调用execute方法

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

会调用到executeOnExecutor方法:他的参数是一个Executor,和需要输入到工作线程执行的参数数据

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        ...

        onPreExecute();

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

        return this;
    }

忽略一些过滤代码,我们看到执行了上面说到的onPreExecute方法.这个方法是第一个被调用到的方法.这个方法是我们要自己根据设置需要而重写的.
之后就会调用Executor参数的execute方法执行mFuture.那么这个mFuture的run方法就跑了起来.进入参数sDefaultExecutor的execute方法研究一下:

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

可以看到他是一个串行的Executor现在来仔细分析这段代码.首先他造了一个队列,这个队列用来承装实现了Runnable的对象.这些对象就是等待执行的工作线程.mTasks.offer(new Runnable()是吧一个new出来的Runnable对象加入到队列的队尾中.等待执行

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值