源码分析--AsyncTask

查看文档

AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.

AsyncTask使适当的和易用的用户界面线程。这个类允许执行后台操作在UI线程上发布的结果而无需操纵线程和/或处理程序

AsyncTask is designed to be a helper class around Thread andHandler and does not constitute a generic threading framework. AsyncTasks should ideally be used forshort operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by thejava.util.concurrent package such as Executor,ThreadPoolExecutor and FutureTask.

AsyncTask被设计成Thread和Handler的一个辅助类,不构成一个通用的线程框架。asynctasks用于短操作(最多几秒钟)如果你需要保持线程长时间运行的高度推荐你使用各种java.util.concurrent包提供执行 ExecutorThreadPoolExecutorFutureTask.

An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, calledParams, Progress and Result, and 4 steps, calledonPreExecute, doInBackground, onProgressUpdate andonPostExecute.

一个异步任务的耗时计算运行是在后台线程,其执行结果在UI线程。一个异步任务由3个泛型类型定义,称为 ParamsProgress 和 Result,和4个步骤,称为它的

onPreExecute

doInBackground

onProgressUpdate 

onPostExecute

文档给我们提供的例子

 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     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;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }
 

Once created, a task is executed very simply:

 new DownloadFilesTask().execute(url1, url2, url3);
 
好了从文档我们可以对AsyncTask类有了一个大概的了解,我们看一下他的结构

具体看一下上面提到的4个方法

//Runs on the UI thread before doInBackground. 运行在UI线程,在doInBackground之前执行
onPreExecute

//Override this method to perform a computation on a background thread.  重写该方法来实现在一个后台线程中耗时操作
//The specified parameters are the parameters passed to execute by the caller of this task.  该方法的参数是又task执行execute方法时传递进来的参数
//This method can call publishProgress to publish updates on the UI thread. 该方法会调用publishProgress去在子线程更新UI
doInBackground

//Runs on the UI thread after doInBackground. The specified result is the value returned by doInBackground. 运行在UI线程,在doInBackground之后执行,result是doInBackgroud方法返回的
//This method won't be invoked if the task was cancelled. 如果task被取消了将不会执行该方法
onPostExecute

//Runs on the UI thread after publishProgress is invoked.  运行在UI线程,在publishProgress之后执行
//The specified values are the values passed to publishProgress.//values 是由publicProgress传递过来的
onProgressUpdate(Void... values)

//Runs on the UI thread after cancel(boolean) is invoked and doInBackground(Object []) has finished. 运行在UI线程,在doInBackground执行完毕后被调用
 onCancelled

我写的一个小例子,从网络下载一张图片,下载过程中更新进度条,下载完成后隐藏进度条,显示图片

public class MainActivity extends Activity {

    private Context   context;
    private ImageView iv;
    private Handler   handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        context = this;
        iv = (ImageView) findViewById(R.id.iv);
        new GetImageTask().execute("https://p18.qhimg.com/bdr/__85/d/_open360/1217xiaoqingxin/3.jpg");
    }

    private ProgressDialog dialog;

    class GetImageTask extends AsyncTask<String, Integer, File> {
        @Override
        protected void onPreExecute() {

            dialog = new ProgressDialog(context);
            dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            dialog.show();
            super.onPreExecute();
        }

        @Override
        protected File doInBackground(String... params) {

            try {
                File file = new File(context.getCacheDir() + "/img.jpg");

                HttpClient client = new DefaultHttpClient();
                HttpResponse response = client.execute(new HttpGet(params[0]));
                HttpEntity entity = response.getEntity();
                long lenghtOfFile = entity.getContentLength();
                InputStream is = entity.getContent();
                FileOutputStream fos = new FileOutputStream(file);
                // 计算文件长度
                long total = 0;
                byte[] buffer = new byte[2014];
                int len = 0;
                while ((len = is.read(buffer)) != -1) {
                    fos.write(buffer, 0, len);
                    total += len;
                    publishProgress((int) (total * 100.0f / lenghtOfFile));
                }
                fos.flush();
                fos.close();
                is.close();

                return file;

            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            dialog.setProgress(values[0]);
        }

        @Override
        protected void onCancelled(File result) {
            super.onCancelled(result);
        }

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

        @Override
        protected void onPostExecute(File result) {
            super.onPostExecute(result);
            if (dialog != null && dialog.isShowing()) {
                dialog.dismiss();
            }
            iv.setImageBitmap(BitmapFactory.decodeFile(result.getAbsolutePath()));
        }

    }

}


分析AsyncTask,我们从构造方法入手

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {//这里创建了一个WorkerRunnable,他是一个实现了Callable接口的抽象类
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                //设置为后台进程
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams)); //这里执行了doInBackground方法
            }
        };
        //创建一个FutureTask(实现了Runnable接口),将上面的Callable对象传递进来,会在FutureTask的run方法中调用Callable的call()方法,所以doInBackground是后台线程执行的
        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);
                }
            }
        };
    }
创建一个FutureTask(实现了Runnable接口),将上面的Callable对象传递进来,会在FutureTask的run方法中调用Callable的call()方法,所以doInBackground是后台线程执行的,我们继续看postResult

private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
结合sHandler,发送了一个Message

 private static final InternalHandler sHandler = new InternalHandler();
    private static class InternalHandler extends Handler {
        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
        @Override
        public void handleMessage(Message msg) {
            AsyncTaskResult result = (AsyncTaskResult) msg.obj;
            switch (msg.what) { //下面是在UI线程的了
                case MESSAGE_POST_RESULT: //调用finish
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS: //回调onProgressUpdate
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
finish()方法

  private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);  //回调 onCancelled(result)
        } else {
            onPostExecute(result); //回调  onPostExecute(result);上面Handler是UI线程了
        }
        mStatus = Status.FINISHED; //把状态置为FINISHED
    }
再看看publishProgress,同样时Handler

 protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }
好吧,这几个方法的执行时间大概算是了解了


下面看AsyncTask的execute()方法

 /**
     * Executes the task with the specified parameters. The task returns
     * itself (this) so that the caller can keep a reference to it.
     *
     * Note: this function schedules the task on a queue for a single background
     * thread or pool of threads depending on the platform version.  When first
     * introduced, AsyncTasks were executed serially on a single background thread.
     * Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
     * to a pool of threads allowing multiple tasks to operate in parallel. Starting
     * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being
     * executed on a single thread to avoid common application errors caused
     * by parallel execution.  If you truly want parallel execution, you can use
     * the {@link #executeOnExecutor} version of this method
     * with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings
     * on its use.
     * <p>This method must be invoked on the UI thread.
     * @param params The parameters of the task.
     * @return This instance of AsyncTask.
     * @throws IllegalStateException If {@link #getStatus()} returns either
     *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
     * @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
     * @see #execute(Runnable)
     *注意:这个函数让任务是以单线程队列方式或线程池队列方式运行,依赖于平台版本而有所不同。AasyncTask首次引入时,这个函数会让任务以后台单线程串行方式执行     *从android.os.Build.VERSION_CODES.DONUT(android 1.6)开始,它让允许任务在线程池中多任务并行执行。但在 android.os.Build.VERSION_CODES.HONEYCOMB           *(android 3.0)之后,它又回去了,变成了单线程执行的模式,原因是多线程并行执行容易引发问题。 如果你真想并行执行任务,你可以使用另外一个版本:             *使用THREAD_POOL_EXECUTOR参数的executeOnExecutor方法,但要注意使用警告提示
     */
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
executeOnExecutor

    /**
     * Executes the task with the specified parameters. The task returns
     * itself (this) so that the caller can keep a reference to it.
     *
     * <p>This method is typically used with {@link #THREAD_POOL_EXECUTOR} to
     * allow multiple tasks to run in parallel on a pool of threads managed by
     * AsyncTask, however you can also use your own {@link Executor} for custom
     * behavior.
     *
     * <p><em>Warning:</em> Allowing multiple tasks to run in parallel from
     * a thread pool is generally <em>not</em> what one wants, because the order
     * of their operation is not defined.  For example, if these tasks are used
     * to modify any state in common (such as writing a file due to a button click),
     * there are no guarantees on the order of the modifications.
     * Without careful work it is possible in rare cases for the newer version
     * of the data to be over-written by an older one, leading to obscure data
     * loss and stability issues.  Such changes are best
     * executed in serial; to guarantee such work is serialized regardless of
     * platform version you can use this function with {@link #SERIAL_EXECUTOR}.
     *
     * <p>This method must be invoked on the UI thread.
     *
     * @param exec The executor to use.  {@link #THREAD_POOL_EXECUTOR} is available as a
     *              convenient process-wide thread pool for tasks that are loosely coupled.
     * @param params The parameters of the task.
     *
     * @return This instance of AsyncTask.
     *
     * @throws IllegalStateException If {@link #getStatus()} returns either
     *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
     *
     * @see #execute(Object[])
     */
    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        if (mStatus != Status.PENDING) { //首先判断AsyncTask的状态,首次默认的是PENDING
            switch (mStatus) {
                case RUNNING: //如果当前时RUNNING,也就是正在执行会抛出下面的异常
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
                case FINISHED://如果状态为FINISHED,也就是说已经执行完了,会抛下面的异常
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
            }
        }

        mStatus = Status.RUNNING; //状态置为RUNNING

        onPreExecute(); //调用该方法还是属于UI线程

        mWorker.mParams = params;//传递参数
        exec.execute(mFuture);

        return this;
    }
上面的方法可以看出,

1. 一个正在执行的AsyncTask任务,再次调用execute方法会抛 Cannot execute task: the task is already running异常,

2.一个执行过的AsyncTask任务,再次调用execute方法会抛 Cannot execute task: the task has already been executed (a task can be executed only once异常,


我们继续往下看, 最终调用了 exec.execute(mFuture);  

从execute()方法中看出参数exec即一个名为 sDefaultExecutor的变量, 

  private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
 public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
即 exec是一个SerialExecutor类,它里面的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() {  //向队列中添加一个Runnable
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }
<span style="white-space:pre">	</span>//从队列中取出一个Runnable对象赋值为mActive,再调用THREAD_POOL_EXECUTOR.execute(mActive);
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

线程池,

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
线程池的初始化 
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); //CPU_COUNT进程数
    private static final int CORE_POOL_SIZE = CPU_COUNT + 1; //核心线程数=CPU_COUNT数+1
    private static final int MAXIMUM_POOL_SIZCPU_COUNT= CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE = 1;

AsyncTask的版本不同,实现原理不同

详细区别 https://blog.csdn.net/pipisky2006/article/details/8535454