AsyncTask源码分析

简介:

关于AsyncTask的用法可以参看前面一篇博客《AsyncTask实现断点续传》,本文只解析AsyncTask的源代码。

AsyncTask.execute方法:

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

execute方法里面直接调用了executeOnexecute方法。

AsyncTask.executeOnexecute方法:

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

3-13行是检测AsyncTask的状态,如果状态不为PENDING,则会抛异常,这也是为什么一个AsyncTask只能被执行一次的原因。14行将状态改为RUNNING,表示该任务正在运行。然后调用AsyncTask的onPreExecute()方法。

由下面代码可以看出,AsyncTask有三种状态:PENDING(未运行)、RUNNING(正在运行)、FINISHED(已运行完毕)。

public enum Status {
    /**
     * Indicates that the task has not been executed yet.
     */
    PENDING,
    /**
     * Indicates that the task is running.
     */
    RUNNING,
    /**
     * Indicates that {@link AsyncTask#onPostExecute} has finished.
     */
    FINISHED,
}

FutureTask代码:

public class FutureTask<V> implements RunnableFuture<V> {
    ......
    //构造方法传入一个Callable对象
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
    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();//这里调用了callable.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);
        }
    }
    ......
}

AsyncTask构造方法:

public abstract class AsyncTask<Params, Progress, Result> {
    ......
    /**
     * 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
                return postResult(doInBackground(mParams));
            }
        };
        //创建FutureTask对象的时候传入了mWorker作为Callable
        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源码我们可以看出,run()方法里面调用了c.call(),而AsyncTask 中创建FutureTask的时候传入了mWorker,所以FutureTask.run()方法里面c.call()调用的是mWorker对象的 call()方法,而AsyncTask里mWorker重写了call方法,即上面8-14行,所以c.call()会执行到 mWorker.call()方法来。call方法里面11行将线程的优先级设置为后台线程,这样当多个线程并发后很多无关紧要的线程分配的CPU时间将 会减少,有利于主线程的处理。

接下来11行执行了doInBackground(mParams)方法,通常我们会重写该方法来实现业务逻辑操作。然后执行postResult 方法,并且将结果返回给FutureTask(因为是FutureTask.run方法调用的此call方法,所以需要返回结果到 FutureTask.run方法)。这里我们先看看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是InternalHandler对象。

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

由第9行代码可知最终会执行AsyncTask的finish方法,代码如下:

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

finish的作用是如果task被取消了就执行onCancelled方法,如果没有被取消而是正常执行完毕,则执行onPostExecute 方法(这也是为什么task被调用了cancel方法,不会执行onPostExecute的原因)。最后将task的状态标记为FINISHED。

上面说到mWorker.call会将执行结果返回给FutureTask.run()方法并且继续往下执行,我们再次看看FutureTask.run方法(20-30行):

boolean ran;
try {
     result = c.call();
     ran = true;
} catch (Throwable ex) {
     result = null;
     ran = false;
     setException(ex);
}
if (ran)
     set(result);

由上面代码可以看到,执行完c.call后,会执行set(result)方法。

protected void set(V v) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = v;
        UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
        finishCompletion();
    }
}

最终会执行finishCompletion()方法。

private void finishCompletion() {
    // assert state > COMPLETING;
    for (WaitNode q; (q = waiters) != null;) {
        if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
            for (;;) {
                Thread t = q.thread;
                if (t != null) {
                    q.thread = null;
                    LockSupport.unpark(t);
                }
                WaitNode next = q.next;
                if (next == null)
                    break;
                q.next = null; // unlink to help gc
                q = next;
            }
            break;
        }
    }
    done();
    callable = null;        // to reduce footprint
}

看到21行代码,会执行FutureTask的done()方法,而这个方法在AsyncTask构造函数中初始化FutureTask对象的时候被重写了。

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

这里主要是验证postResult是否被调用了,如果没有被调用着调用postResult函数,因为前面mWorker.call方法里面调用过了,所以这里不错操作。

顺便提一下,在AsyncTask的doInBackground方法中如果需要更新UI的话,则调用AsyncTask的publishProgress方法即可:

protected final void publishProgress(Progress... values) {
     if (!isCancelled()) {
         sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
                 new AsyncTaskResult<Progress>(this, values)).sendToTarget();
     }
}

publishProgress方法最终也会通过sHandler来调用AsyncTask的onProgressUpdate方法,一般我们如果需要获取进度的话都需要重写AsyncTask的onProgressUpdate。

好了,AsyncTask的源码也分析完了。再次总结一下Asynctask使用的注意事项:

  1. 异步任务的实例必须在UI线程中创建。
  2. execute(Params… params)方法必须在UI线程中调用。
  3. 不要手动调用onPreExecute(),doInBackground(Params… params),onProgressUpdate(Progress… values),onPostExecute(Result result)这几个方法。
  4. 不能在doInBackground(Params… params)中更改UI组件的信息。
  5. 一个任务实例只能执行一次,如果执行第二次将会抛出异常。
相关文章
|
10月前
Volley源码分析(一)
Volley源码分析(一)
131 0
|
Java Android开发
AsyncTask
http://developer.android.youdaxue.com/reference/android/os/AsyncTask.html public abstract class AsyncTask extends Object java.lang.Object android.os.AsyncTask<Params, Progress, Result>
128 0
|
Android开发
【Android 异步操作】AsyncTask 异步任务 ( 参数简介 | 方法简介 | 使用方法 | AsyncTask 源码分析 )
【Android 异步操作】AsyncTask 异步任务 ( 参数简介 | 方法简介 | 使用方法 | AsyncTask 源码分析 )
172 0
|
Java Android开发
【Android 异步操作】AsyncTask 异步任务 ( FutureTask 模拟 AsyncTask 执行过程 | AsyncTask 执行过程回顾 | FutureTask 分析 )
【Android 异步操作】AsyncTask 异步任务 ( FutureTask 模拟 AsyncTask 执行过程 | AsyncTask 执行过程回顾 | FutureTask 分析 )
149 0
线程池源码分析_01 FutureTask源码分析
文章参考:硬核手撕Java线程池FutureTask源码
IntentService源码分析
我们知道Service是运行在主线程的,主线程中不能进行耗时操作,否则会发生ANR。Service中的发生ANR的超时时间是20s。 有时候我们需要应用在后台默默做一些任务,例如上传文件等。如果我们采用Service,则需要我们自己手动开启新的线程。如果我们不想 自己开启线程怎么办,IntentService就出现了。
|
iOS开发
fishhook源码分析
最早了解到[fishhook](https://github.com/facebook/fishhook)是看了下面两篇文章之后,顿时让我觉得这是一个非常好的东西。总共210行代码,收获了1500+个star,神作啊。 1. [iOS Lazy Binding](http://www.atatech.org/articles/68014),使用fishhook拦截NSSetUncaughtE
2395 0
HandlerThread原理与应用
HandlerThread  在理解了Handler的原理之后,我们知道在一个子线程中创建一个Handler不能缺少了Looper.prepare()和Looper.loop()两个方法,具体的原因这里不再赘述,不熟悉原理的可以先看下另一篇文章Handler的原理解析. 本篇文章主要是讲解HandlerThread的使用的。
1149 0
|
移动开发 Java 开发者
Stresstester源码分析
stresstester-1.0.jar是早期淘宝的一个压力测试工具,很方便开发人员进行本地代码的压力测试,其他专门压力测试工具也有很多,如:jmeter loadrunner 等等,本篇文章主要讲一下stresstester的源码设计
10582 0
|
大数据 DataX 分布式计算
gobblin 源码分析
最近,开始搞些大数据相关的内容,遇到的第一个问题,就是数据入库,小白刚入手,又不想写太多代码,于是从网上找,入库手段很多: DataX,Sqoop,以及Flume 等以及直接使用 Spark 进行入库,想了下当下的场景(不是简单的倒库,要从kafka拉...
1380 0