AsyncTask的深入理解

AsyncTask的深入理解

一、AsyncTask

1、初步理解
AsyncTask是一个轻量级的异步任务类,底层封装了Thread和Handler,AsyncTask不适合进行特别耗时的后台任务,特别耗时建议使用线程池。

public abstract class AsyncTask<Params,Progress,Result>

AsyncTask为泛型抽象类,其中三个泛型参数的含义为:
(1)Params:参数类型
(2)Progress:后台执行任务的进度
(3)Result:返回结果的类型

AsyncTask的5个核心方法:
(1)onPreExecute()在主线程中执行,在异步任务执行之前,此方法会被调用,一般可以用于做一些准备工作。
(2)doInBackground(Params…params)在线程池中执行,此方法用于执行异步任务,params参数表示异步任务的输入参数。在此方法中可以通过publishProgress方法来更新任务的进度,publishProgress方法会调用onProgressUpdate方法。另外此方法需要返回计算结果给onPostExecute方法。
(3)onProgressUpdate(Progress…values)在主线程中执行,当后台任务的执行进度发生改变时此方法会被调用。
(4)onPostExecute(Result result)在主线程中执行,在异步任务执行之后,此方法会被调用,其中result参数是后台任务的返回值,即doInBackground的返回值。
(5)onCancelled()主线程中调用,当异步任务被取消时调用,onPostExecute()方法不会被调用。
示例:

private class DownloadTask 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));//调用onProgressUpdate,并把值给它
        if (isCancelled())
            break;
        }
    return totalSize;//返回值给到onPostExecute
}
protected void onProgressUpdate(Integer... progress) {
    setProgress(progress[0]);
}
protected void onPostExecute(Long result) {
    showDialog("Downloaded " + result + " bytes");
}
}

要执行我们上述所写的函数时

new DownloadTask().execute(url1,url2,url3);

注意点
(1)AsyncTask必须在主线程中加载,Android4.1后ActivityThread的main方法会调用AsyncTask的init方法,来帮助我们加载,所以这一点就不用担心了。
(2)AsyncTask的对象必须要在主线程中创建。
(3)execute方法必须在UI线程调用。
(4)一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常。
(5)在Android 1.6之前,AsyncTask是串行执行任务的,Android 1.6的时候AsyncTask开始采用线程池里处理并行任务,但是从Android 3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务。尽管如此,在Android3.0以及后续的版本中,我们仍然可以通过AsyncTask的executeOnExecutor方法来并行地执行任务。

2、详细理解
(1)从execute方法入手

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

得知里面还是调用了executeOnExecutor方法,sDefaultExecutor实际上是一个串行的线程池,一个进程中所有的AsyncTask全部在这个串行的线程池中排队执行。接下来看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;
}
。。。
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);
        }
    }
};

mStatus上面的这个状态,是判断execute是不是第一次调用,如果不是则抛出异常。由上述函数可得知:(1)系统首先把AsycTask的Params参数封装成FutureTask对象(并发类,充当Runnable,Future能得到计算结果)(2)通过exec.execute(mFuture);来启动线程池。
接下来看下,线程池的一个执行过程。

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
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);
        }
    }
}

(3)把Futuretask交给SerialExecutor的execute方法去处理。(4)execute把FutureTask对象插入到任务队列mTasks中。(5)判断当前有没有在活动的AsyncTask任务,没有的话调用scheduleNext执行下个任务。从这里也能看出任务是一个一个执行的,因此AsyncTask为串行。

AsyncTask中有两个线程池(SerialExecutorTHREAD_POOL_EXECUTOR)和一个
Handler(InternalHandler),其中线程池SerialExecutor用于任务的排队,而线程池
THREAD_POOL_EXECUTOR用于真正地执行任务,InternalHandler用于将执行环境从线程池切换到主线程。

上述看完任务的排队过程,接下来看doInBackground方法什么时候调用的
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));
    }
};

mTaskInvoked.set(true);表示当前任务已经被调用过,然后doInBackground方法被调用,并将结果传给postResult函数,接下来看看postResult函数的一个实现:

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

从上述函数中可得知,postResult主要通过sHandler发送了一个消息。接来下来看sHandler的是啥

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) {
            case MESSAGE_POST_RESULT:
                result.mTask.finish(result.mData[0]);
            break;
            case MESSAGE_POST_PROGRESS:
            result.mTask.onProgressUpdate(result.mData);
            break;
        }
    }
}

sHandler是一个静态的Handler对象,能将执行环境切换到主线程,因此这个Handler对象必须在主线程中创建,所以间接要求AsyncTask的类必须在主线程中加载,否则将无法工作。sHandler接收到MESSAGE_POST_RESULT这个消息后,会调用AsyncTask的finish方法,接来下看看这个方法的实现:

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

可得知,如果AsyncTask被取消了,则调用onCancelled方法,否则则调用onPostExecute方法。至此,AsyncTask运行流程已经过完一遍。

上述说的流程是一个串行的流程,因为我们一开始执行的是AsyncTask的execute方法,里面帮我们调用executeOnExecutor(sDefaultExecutor, params);这个方法,并帮我们传入一个sDefaultExecutorsDefaultExecutor实际上是一个串行的线程池。如果我们想要AsyncTask并行,就需要直接调用executeOnExecutor这个方法,并传入一个并行的线程池,如:

new MyAsyncTask("").
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
发布了14 篇原创文章 · 获赞 45 · 访问量 2453

猜你喜欢

转载自blog.csdn.net/weixin_42683077/article/details/99648752
今日推荐