AsyncTask原理

五个核心方法

  • onPreExecute()
    此方法在主线程中执行,在异步任务执行之前,此方法会被调用,一般用于一些准备工作,例如下载进度条的初始化。

  • doInBackground(Params… params)
    此方法在子线程中执行,用于执行异步任务,注意这里的params就是AsyncTask的第一个参数类型。在此方法中可以通过调用publicProgress方法来更新任务进度,publicProgress会调用 onProgressUpdate 方法。

  • onProgressUpdate(Progress… values)
    此方法在主线程中执行,values的类型就是AsyncTask传入的第二个参数类型,当后台任务的执行进度发生变化时此方法执行。

  • onPostExecute(Result result)
    此方法在主线程中执行,在 doInBackground 方法执行完成以后此方法会被调用,其中result的类型就是AsyncTask传入的第三个参数类型,它的值就是doInBackground方法的返回值。

  • execute(Params… params)
    触发异步任务的执行。

  • publishProgress(Progress… values)
    一般在doInBackground中调用,来开启进度更新

注意

  • AsyncTask的实例必须在UI线程中创建
  • execute必须在UI线程中调用
  • 不能在doInBackGround中更改UI组件信息
  • 一个AsyncTask的实例只能执行一次任务,执行第二次会抛出异常

AsyncTask的实现基本原理

相关系统类:
LinkedBlockingQueue、ThreadPoolExecutor、Handler、Callable、FutureTask、Executors、ArrayDeque

内部类:
Status:枚举类,有PENDING、RUNNING、FINISHED三种状态

SerialExecutor:Executors对象,分发任务给ThreadPoolExecutor,让任务顺序执行

WorkerRunnable< Params, Result>:Callable对象,表示任务,封装执行任务的逻辑,以及返回执行结果

InternalHandler:内部的Handler,通过主线程的Looper构造。AsyncTask最后其实也是通过Handler来把结果返回给UI线程。

AsyncTaskResult:原始结果被封装入成此对象,并绑定到Message上被Handler发出去

首先我们会创建一个AsyncTask的实例:

public AsyncTask() {
    //实例化一个任务实例,它实现了Callable接口,可返回结果
    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            ...
            Result result = doInBackground(mParams);
            Binder.flushPendingCommands();
            return postResult(result);
        }
    };

    //传入了Callable任务实例,封装成FutureTask,可被线程执行,任务执行完毕,调用done方法
    mFuture = new FutureTask<Result>(mWorker) {
        @Override
        protected void done() {
           ...
        }
    };

创建好之后,已经定义好了任务体,获得结果只需要mFuture.get()即可。创建好实例,重写过相关方法后,就会调用AsyncTask实例的execute方法:

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

这里有调用了executeOnExecutor,并且多了一个参数sDefaultExecutor用来分发任务,让任务顺序执行。跟踪executeOnExecutor:

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

为什么AsyncTask实例只能执行一次?
从if条件判断语句看到,如果不是PENDING状态就会抛出异常。而在AsyncTask实例初始化时,mStatus会被置为PENDDING。继续往下看,只要调用execute,状态就会变为RUNNING。

代码逻辑跳入exec.execute(mFuture),exec为SerialExecutor实例,参数为FutureTask实例。因此,接下来查看SerialExecutor类:

private static class SerialExecutor implements Executor {
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    Runnable mActive;
    //核心方法,参数为Runnable。FutureTask实现了Runnable接口(实际上是RunnableFuture接口)
    public synchronized void execute(final Runnable r) {
        //加入任务到队尾。并且,重新封装任务,加入scheduNext方法,使每个任务执行完后,自动执行取队首任务执行。
        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);
        }
    }
}

到这里似乎断了,因为发现调用没有返回结果的方法。这里要提到FutureTask,在调用exec.execute(mFuture)后,在构造方法中创建的mFuture被传入exec对象,上面被最终执行的mActive其实引用的是FutureTask对象,FutureTask是个可管理的异步任务,任务执行完之后,会调用done方法,之后获取结果,又最终调用到postResult传递结果到UI:

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

可见也是通过Handler传递消息,最后查看InternalHandler类:

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

如果任务正在执行,则最终调用onProgressUpdate,若任务执行完毕则最终调用到onPostExecute

既然Asynctask的实例一次只能执行一次,那么要执行多次任务怎么办?
那就创建多个Asynctask实例来执行任务啊,另外,任务分发器sDefaultExecutor、线程池THREAD_POOL_EXECUTOR、内部Handler:InternalHandler都是静态的,虽然创建了多个实例,但是这些都是共享的。

在Android1.6之前,AsyncTask是串行执行任务,在1.6以后,改为在线程池里并行处理任务,在3.0以后,又改为在线程池里串行执行任务。

推荐阅读:
Android AsyncTask 源码解析
都是鸿洋大神写的,很赞~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值