Android AsyncTask工作原理分析

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u012489412/article/details/79473931

Android AsyncTask工作原理分析

闲来无事又看了一下android多线程的部分源码,由于自己经常会忘记一些知识,用博客记录一下,也算加强记忆,同时也分享自己的一些理解,以此来相互学习。本文源码主要基于android 8.0,也就是api26,如发现版本不一致的,可切换到该版本下,查看。

  • 一、AsyncTask概述
  • 二、AsyncTask的工作流程

一、AsyncTask概述

1.1 类的介绍和使用

AsyncTask是一个轻量级的异步任务类,我们看一下它的声明

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

它是一个抽象类,所以我们平时使用时,先继承它,用子类去实现和重载它相关的方法。

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

1.2主要方法介绍

由于它是抽象类,我们继承后主要实现和重载了3个抽象方法:
onPreExecute():在主线程中执行,在异步任务执行之前执行,主要用来做一些准备工作。
doInBackground(Params… params):在子线程中执行,params为异步任务的输入参数。
onPostExecute(Result result):在主线程中执行,异步任务执行后,调用此方法,result为执行后的结果数据的返回。
除此之外,我们经常还会用到的,还有:
onProgressUpdate(Progress… values) :在主线程中执行,子线程任务进度发生变化时被调用,通常用来更新进度条。

这些方法的调用顺序依次为onPreExecute(),doInBackground(Params… params),onProgressUpdate(Progress… values),onPostExecute(Result result)

二、AsyncTask的工作流程

我们继承这个类和实现后,主要使用如下:

new DownloadFilesTask().execute(url1, url2, url3)

先new了这个类,然后执行了它的execute方法;那我们先从它的构造函数进行分析:

2.1构造函数

我们先看一下构造函数的源码,构造函数主要有3个。

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        this((Looper) null);
    }

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     *
     * @hide
     */
    public AsyncTask(@Nullable Handler handler) {
        this(handler != null ? handler.getLooper() : null);
    }

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     *
     * @hide
     */
    public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);
                }
                return 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);
                }
            }
        };
    }

从构造中可以看出,它主要做了3个方面的工作:
(1)获取一个主线程的Handler,来初始化mHandler ,如果没有形参callbackLooper是空,或者callbackLooper 是主线程的Looper,就通过getMainHandler(),来初始化;否则,就直接new Handler(callbackLooper)。

getMainHandler()里面又做了什么工作呢?
看一下它的源码:

    private static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;
        }
    }

它主要是构造了一个单例的sHandler返回给mHandler;在这里我们看到new的是一个InternalHandler,它里面又是什么呢?
我们再看一下InternalHandler的源码:

    private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }

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

它是一个静态内部类,主要实现了handleMessage的方法,handleMessage中主要对2类消息进行了处理,一类是MESSAGE_POST_RESULT消息,接收到这个消息后finish了当前的的任务,这里主要可以看result.mTask,不详细介绍;另一类消息是MESSAGE_POST_PROGRESS,接收到这个消息后主要执行了当前任务的onProgressUpdate方法,更新进度。
(2)再回构造函数,执行完Handler的初始化,然后new了一个继承WorkerRunnable的匿名内部类赋值给mWorker;WorkerRunnable是一个静态抽象内部类

    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
    }

从这里可以看出,WorkerRunnable是一个静态抽象内部类,大家都知道抽象类不能直接被实例化的,所以这里它使用了匿名内部类的方式进行对mWorker进行实例化,刚开始还觉得有点别扭。
同时,我们也看到它继承了Callable接口,并且在实例化时,实现了call方法。
(3)再回构造函数,对mFuture进行了实例化,重载了done()方法,在done()里面主要调用了postResultIfNotInvoked(Result result)这一方法,我们打开这个方法的源码

    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

从中可以看出,它又调用了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只是负责发消息;然后mHandler接收和处理消息,这就和前面对应上了。

好了构造函数看完了,我们接下来看execute方法,看到这里其实还是迷糊的。当我们看完execute就不觉得迷糊了,思路就开始清晰了。

2.2execute方法分析

我们还是直接打开源码

   public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(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;
    }

从中我们可以看出execute调用了executeOnExecutor方法,在executeOnExecutor方法里先确定了当前任务的状态,然后调用了onPreExecute(),这里就执行到我们的任务前准备的方法了,然后又执行了exec.execute(mFuture);exec我们入参的是sDefaultExecutor对象,这个sDefaultExecutor是被一个SerialExecutor内部类进行实例化的,可以在源码中跟踪到。
这个SerialExecutor又做了什么工作呢?
看一下源码:

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

可以看出SerialExecutor主要是做了排队,通过线程池THREAD_POOL_EXECUTOR执行mActive任务,我们任务开始执行后,又到了哪里呢?我们看到mActive是从mTasks.poll()来得,mTasks又在mTasks.offer的Runnable的匿名对象中执行了run方法中的r.run(),这个r是我们在executeOnExecutor方法的exec.execute(mFuture)语句中传入的mFuture对象。mFuture我们在构造函数中进行了实例化。
这里很重要
当mActive任务呗执行时,run方法被回调,根据入参可知道实际上是mFuture的run()方法就会执行,mFuture是被FutureTask实例化,我们来一下它的run方法源码

    public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, 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的call方法被调用了,c是什么呢?c就是入参的mWorker对象,call()方法就是在AsyncTask的构造函数里mWorker被实例化时的实现的那个方法,这里mFuture就和mWorker完全关联起来了

call()方法被调用时,执行了result = doInBackground(mParams);从这一段可以看到,我们的doInBackground方法也被执行了。执行完后,postResult将会被执行,发送了一个msg.what为MESSAGE_POST_RESULT的消息,
mHandler接收到MESSAGE_POST_RESULT消息后,执行了
result.mTask.finish(result.mData[0]);这里就调用了mTask的finish方法,我们看一下finish方法

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

finishi方法,判断了,是否可以取消,不能取消时就执行onPostExecute方法。可取消时执行onCancelled方法。这里可以看到任务可以被取消,当我们经常离开activity时,任务没执行完时,可以取消掉。
我们的任务到这里就走完了。有人说我们的的更新进度方法还没执行呢?我们可以看到api里面有提供一个publishProgress的方法,我们可在实现doInBackground方法中,多次调用publishProgress方法,发送MESSAGE_POST_PROGRESS消息,当我们的mHandler接收到该消息就会回调onProgressUpdate方法,我们重载的onProgressUpdate方法就被调用了,就可以在主线程中更新进度条了。
到这里我们的流程就完全清楚了。
execute流程

Created with Raphaël 2.1.0executeexecuteexecuteOnExecutorexecuteOnExecutoronPreExecuteonPreExecutemWorker.call()mWorker.call()doInBackgrounddoInBackgroundonProgressUpdateonProgressUpdateonPostExecuteonPostExecute调用执行了mFuture.run()中执行到执行了publishProgress调用postResult->mHandler分发MESSAGE_POST_RESULT消息,在finish方法中被调用

好了,分享到这里就结束了,感谢细心看完,如果有不理解的可以私信我。谢谢大家!

展开阅读全文

没有更多推荐了,返回首页