AsyncTask的使用和源码分析

官方文档:
https://developer.android.com/reference/android/os/AsyncTask.html

AsyncTask是一个封装了Thread和Handler的帮助类。使用该类,我们无需自行操作Thread和Handler,就可以完成后台任务处理,并将结果返回到主线程。

先来看AsyncTask类的声明:
package android.os;

public abstract class AsyncTask<Params, Progress, Result> {
}

可以看到,AsyncTask定义了三个泛型类型参数Params,Progress,Result。各参数含义如下:
(1).Params,执行任务需要使用的参数。
(2).Progress,当前任务执行的进度。
(3).Result,任务执行完成返回的结果。

如果某一个类型不需要传入参数时,可以使用Void类型:
private class MyTask extends AsyncTask<Void, Void, Void> { ... }

在使用中,主要重写的有以下几个方法:
(1).void onPreExecute(),主线程中执行,在任务执行之前,该方法会被回调。
(2).Result doInBackground(Params... params),该方法在子线程中执行,用来处理耗时操作,不能在这里更新UI。
(3).void onProgressUpdate(Progress... values),主线程中执行,显示当前任务执行的进度。
(4).void onPostExecute(Result result),主线程中执行,任务执行完成之后,该方法被回调,参数即是执行任务返回的结果。

使用AsyncTask时,必须要重写doInBackground(Params... params)方法,因为该方法是abstract的。其余的方法是否需要重写,根据自身的功能需求来决定。一般来说,会同时重写onPostExecute(Result result)方法。

AsyncTask的实现类示例代码如下:
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");
     }
 }


然后调用AsyncTask对象的execute(Params... params)方法启动任务。


AsyncTask的执行,经过四个步骤:
1.onPreExecute(),当AsyncTask在UI线程上启动任务后,该方法立即执行。这方法通常用于做一些初始化设置,例如在显示一个进度条。
2.doInBackground(Params...),当onPreExecute()执行完成后,该方法立即调用。这方法用于执行耗时操作。execute()方法的参数会传到这里,执行的结果必须在这步返回。在执行过程中,可以调用publishProgress(Progress...)来更新任务的进度。
3.onProgressUpdate(Progress...),当publishProgress(Progress...)执行后,该方法被回调。该方法用于当后台任务还在进行时,在用户界面显示进度。
4.onPostExecute(Result), 当任务执行完成,执行的结果会作为一个参数传递到该方法。我们可以在该方法中刷新UI。

在使用AsyncTask时需要注意以下几点:
(1).必须在主线程中创建AsyncTask对象。
(2).execute(Params... params)方法必须在主线程中调用。
(3).不要手动调用onPreExecute(),onPostExecute(Result),doInBackground(Params...),onProgressUpdate(Progress...)方法。
(4).创建一个AsyncTask对象,只能调用一次execute()方法。

AsyncTask在首次推出时,任务是在单个子线程中串行的执行。从Android 1.6版本开始,AsyncTask内部使用一个线程池,并允许多个任务同时执行。再到Android 3.0版本,AsyncTask被再一次修改,在单线程中执行任务,以避免并行执行引发的应用错误。
如果我们想并行执行任务,可以调用executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,Params... params)方法。

下面我们从执行流程上对AsyncTask核心部分源码进行分析,这里以最新的Android6.0版本为例。

首先,创建AsyncTask对象,并调用其execute(Params... params)方法。
@MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

方法内部只有一行,调用了executeOnExecutor(Executor exec, Params... params)方法。
@MainThread
    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;
    }
进入方法之后,首先有if判断,从这里可以看出为什么一个AsyncTask对象只能调用一次execute()方法。然后,把状态置为RUNNING,执行 onPreExecute(),将传入的参数赋值给mWorker.mParams,接下来使用sDefaultExecutor对象执行mFuture。

我们再来看看mWorker和mFuture对象。当AsyncTask对象被创建时,会调用其构造方法。
/**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                return postResult(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);
                }
            }
        };
    }


在构造方法中,创建一个实现了WorkerRunnable抽象类的对象mWorker,并在其call()方法中,执行doInBackground()方法,将参数mParams传入进去。doInBackground()方法执行完毕后,返回postResult(result)的执行结果。另外创建了一个将要执行的任务FutureTask赋值给mFuture变量,并将上述mWorker传入进去。


进入postResult()方法,这里看到了我们熟悉的Handler和Message。
private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

接下来,我们找到Handler类。
private static class InternalHandler extends Handler {
        public InternalHandler() {
            super(Looper.getMainLooper());
        }

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

可以看到,InternalHandler类接收两种消息,MESSAGE_POST_RESULT和MESSAGE_POST_PROGRESS。当InternalHandler接收到进度通知的消息MESSAGE_POST_PROGRESS时,会执行 onProgressUpdate()方法。接收到任务执行完毕返回结果的消息时,会执行finish()方法。

我们再来看看finish()方法。
private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

可以看到,在finish()内部, onPostExecute()方法被执行。

到这里,大致流程已基本结束。我们再回到executeOnExecutor()方法的最后一行,exec.execute(mFuture)。这里的exec其实就是成员变量sDefaultExecutor。

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
            TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

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

sDefaultExecutor是SerialExecutor类的实例,内部定义了一个任务队列,当调用其execute()方法,会将任务加入队列。每取出一个任务,加入THREAD_POOL_EXECUTOR线程池中执行。当一个任务执行完毕之后,通过scheduleNext()方法再去执行下一个任务。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值