AsyncTask源码解析

作为异步消息机制,AsyncTask可替代Thread+Handler,以更新UI线程,

先上一个例子,感受一下AsyncTask

AsyncTask是抽象类,因此首先需要继承它,并实现它为实现的方法。在继承时,需要三个泛型参数,

params :执行任务时,传入的参数,在后台执行。

Progress:任务执行过程中,需要显示当前进度的单位类型

Result:执行完毕后,返回结果的类型



class DownloadTask extends AsyncTask<Void, Integer, Boolean> {  
  
    @Override  
    protected void onPreExecute() {  
        progressDialog.show();  
    }  
  
    @Override  
    protected Boolean doInBackground(Void... params) {  
        try {  
            while (true) {  
                int downloadPercent = doDownload();  
                publishProgress(downloadPercent);  
                if (downloadPercent >= 100) {  
                    break;  
                }  
            }  
        } catch (Exception e) {  
            return false;  
        }  
        return true;  
    }  
  
    @Override  
    protected void onProgressUpdate(Integer... values) {  
        progressDialog.setMessage("当前下载进度:" + values[0] + "%");  
    }  
  
    @Override  
    protected void onPostExecute(Boolean result) {  
        progressDialog.dismiss();  
        if (result) {  
            Toast.makeText(context, "下载成功", Toast.LENGTH_SHORT).show();  
        } else {  
            Toast.makeText(context, "下载失败", Toast.LENGTH_SHORT).show();  
        }  
    }  
}  
接着运行任务:只需要一句

new DownloadTask().execute();  

介绍一下重载的方法:

onPreExecute():

方法执行前的一些动作,在后台线程开启之前工作,这里还是UI线程,可以更新UI。

doInBackground():

在后台运行的方法,处理一些耗时操作,任务一旦完成就返回执行结果,当然如果第三个参数Result设为Void的话,就会不返回执行结果。切记:这里执行的是在后台线程里运行的代码,因此不要在这里更新UI,如果想更新UI,可以在这里调用publishProgerss(Progress...),这样就可以更新UI了,(现在先说一个大概的原因:publishUpdate(Progress.. )执行之后,会自动调用onProgressUpdate(Progress...),这一实现是通过Handler解决的,稍后,我会从代码角度细细解释)。

onProgressUpdate(Progress...):

在执行过程中,publishUpdate(Progress.. )执行之后,会自动调用onProgressUpdate(Progress...),onProgressUpdate方法中的参数,是后台线程传递过来的数据,以更新UI。

onPostExecute(Result):

任务完成之后,进行的操作。当后台线程执行完毕后,返回的结果就是这里的Result参数,然后自动调用该方法(也是通过Handler消息机制完成,后面会细细解释),以更新UI线程。


好了,下面进入正题,解析AsyncTask源码(我这里是API17)

构造函数:

public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {//初始化WorkRunnable对象(其实就是Callable对象)
            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) {//初始化FutureTask对象,并将mWorker(即Callabale对象)当做参数传入

            @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);
                }
            }
        };
    }
WorkRunnable类其实是实现了Callable接口

FutureTask类实现了RunnableFuture接口,从名字上看来,与Runnable,Future有关,其实RunnableFuture 就是继承了Runnable和Future接口,说白了,就是FutureTask既有Future特性,又有Runnable特性,(Future)


为了下面的分析更明朗,我需要花一些时间解释一下Future,FutureTask

Future:

就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。说白了就是对传统的Runnable,Callable进行增强,增强他们的控制能力。

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}


  • cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。
  • isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
  • isDone方法表示任务是否已经完成,若任务完成,则返回true;
  • get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
  • get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。

  也就是说Future提供了三种功能:

  1)判断任务是否完成;

  2)能够中断任务;

  3)能够获取任务执行结果。

  因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了下面的FutureTask。

前面已经提到FutureTask实现了Future,既然Future是对Runnable,Callable控制能力的增强,那么FutureTask里面必有Runnable和Callable的身影。果不其然,FutureTask的构造方法:

public FutureTask(Callable<V> callable) {}
public FutureTask(Runnable runnable, V result) {}
好了知识补充先到这里,还有一些后面用到再说。

回到AsyncTask:

既然任务运行只需要执行AsyncTask的实现类.execute(),那么就从这里入手,看看到底任务到底是怎么运行的。

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

execute()调用了executeOnExcutor(sDefaultExecutor ,params),那么sDefaultExecutor是什么呢?追根溯源是SerialExecutor对象

 private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
  public static final Executor SERIAL_EXECUTOR = new SerialExecutor();


看看executeOnExcutor(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;
    }

上面的代码先进行任务所处状态的判断,以保证该任务只能运行一次,否则就会报异常,判断后,至当前任务状态为RUNNING,于是开始了执行任务,正如前面介绍,先执行了onPreExecutor(),然后将执行任务所需要的Params传递给了前面AsyncTask构造函数里已经实例化的mWorker对象(即Callable对象),然后又执行了exec.executor(mFuture);这里的mFuture也是前面AsyncTask构造函数里实例化的FutureTask对象。那么exec是谁的对象引用呢?其实就是传递进来的sDefaultExecutor参数,就是SerialExecutor 对象,因此这里实际上是执行SerialFuture里面的executor(mFuture),下面来看看:

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


里面又运行了r.run(),这里的r就是mFuture,即FutureTask对象,也就是说实际执行了FutureTask里面的run(),下面再看看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();
                    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);
        }
    }

其他的代码不需要管,只需看result=c.call()这一句,c就是传入的mWorker(Callable对象),也就是调用了mWorker的call(),跟踪了半天,原来真正执行的后台线程在这里,就是mWorker的call()里。再次贴出call()里面执行的内容,如下:

  mWorker = new WorkerRunnable<Params, Result>() {//初始化WorkRunnable对象(其实就是Callable对象)
            public Result call() throws Exception {
                mTaskInvoked.set(true);

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

我们看到,此时,执行了doInBackground(mParams),并返回了结果。下面看看postResult(Result)到底干了什么,

  private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
也就是封装了一下任务的返回结果,封装进了Message里。message.what=MESSAGE_POST_RESULT,

message.object=new AsyncTaskResult<Result>(this,result).

AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }

这里终于出现了我们熟悉的Handler对象,sHandler,看看它在哪里实例化的

   private static final InternalHandler sHandler = new InternalHandler();

InternalHandler类的实现:呵呵,Handler处理消息的函数handleMessage(Message msg)出现了,如下:

private static class InternalHandler extends Handler {
        @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;
            }
        }
    }
前面提到postResult(Result)会发送一个MESSAGE_POST_RESULT消息,从handleMessage方法来看,会执行finish(result.mData[0]),

(一旦进入handleMessage方法就代表着又回到了UI线程,)

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

如果不取消任务的话,会执行onPostExecute(result).由于又回到了UI线程,所以我们说 onPostExecute(result)是在UI线程里运行,可更新UI.

那么何时执行onProgressUpdate(result.data)方法呢?

前面我们提到过一旦执行publishProgress(),就会自动执行onProgressUpdata(result.data),下面从代码角度看看为什么。

 protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }
原来,它里面也是发送了一条消息MESSAGE_POST_PROGRESS,依据前面的分析,在handleMessage里会执行onProgressUpdate(result.data).

好了,现在AsyncTask源码大致解析结束.

最后,大致总结一下流程:

AsyncTask.execute(Params...) ->  AsyncTask.executeOnExecutor(SericalExecutor,Params...)->  AsyncTask.onPreExecute()  ->

SericalExecutor.execute(FutureTask)  ->  FutureTask.run()   -> (进入非UI线程) Callable.call()  ->

AsyncTask.doInBackground(Params...) -> (回到UI线程)AsyncTask.postResult() -> AsyncTask.onPostExecute(Result)   




 


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值