Android异步任务AsyncTask原理(基于Android9.0)

AsyncTask原理

    • 前言
    • AsyncTask介绍
    • 源码分析

前言

在Android开发中经常会通过线程去执行耗时的任务,并且在任务执行完之后通常会用到Handler来更新UI。虽然实现简单,但是有多个任务同时执行时则会显得代码很臃肿。Android提供了AsyncTask,它使得异步任务实现起来更加简单,代码更简洁。

AsyncTask介绍

AsyncTask是一个抽象的泛型类,它有3个泛型参数,分别为Params、Progress和Result。
Params:参数类型,
Progress:后台任务执行进度的类型,
Result:返回结果的类型。
如果不需要某个参数,可以将其设置为Void类型。
AsyncTask如下:

public abstract class AsyncTask {
}

AsyncTask中有4个核心方法:
1、onPreExecute():在主线程中执行。一般在任务执行前做准备工作。

2、doInBackground(Params…params):在线程池中执行。在 onPreExecute方法执行后运行,用来执行耗时操作。在执行过程中可以调用publishProgress(Progress…values)方法来更新进度信息。

3、onProgressUpdate(Progress…values):在主线程中执行。当调用publishProgress(Progress…values)方法时,此方法会将进度更新到UI组件上。

4、onPostExecute(Result result):在主线程中执行。当后台任务执行完成后,会被执行。doInBackground方法得到的结果就是返回的result的值。

源码分析

接下来分析一下AsyncTask的源码。首先看下构造方法:

	/**
     * 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判空
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

        mWorker = new WorkerRunnable() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    result = doInBackground(mParams);//在call方法中调用了doInBackground(mParams)来处理任务并得到结果
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);//最终调用postResult将结果投递出去
                }
                return result;
            }
        };
		//FutureTask是一个可管理的异步任务
        mFuture = new FutureTask(mWorker) {//在这里WorkerRunnable作为参数传递给了FutureTask
            @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);
                }
            }
        };
    }

WorkerRunnable实现call方法,在call方法中调用了doInBackground(mParams)来处理任务并得到结果,并最终调用postResult将结果通过Handler发出去。

FutureTask实现了Runnable和Futrue这两个接口。因此,它可以包装Runnable和Callable,并提供给Executor执行。也可以调用FutureTask自己的run()方法执行。代码如下:

	public class FutureTask implements RunnableFuture {
		...
	}

FutureTask实现RunnableFuture接口

	public interface RunnableFuture extends Runnable, Future {
	    /**
	     * Sets this Future to the result of its computation
	     * unless it has been cancelled.
	     */
	    void run();
	}

RunnableFuture继承Runnable, Future两个接口。

当要执行 AsyncTask 时,需要调用它的 execute方法,代码如下:

	@MainThread
    public final AsyncTask execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

execute方法中又调用了executeOnExecutor方法:

	@MainThread
    public final AsyncTask 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;//将 AsyncTask 的参数传给WorkerRunnable
        exec.execute(mFuture);//exec是传进来的参数sDefaultExecutor

        return this;
    }

这里会首先调用 onPreExecute 方法,将 AsyncTask 的参数传给WorkerRunnable。

从前面我们知道WorkerRunnable作为参数传递给了FutureTask,因此,参数被封装到FutureTask中。接下来
会调用exec的execute方法,并将mFuture也就是前面讲到的FutureTask传进去。

exec是传进来的参数sDefaultExecutor,是一个串行的线程池,SerialExecutor代码如下:

	private static class SerialExecutor implements Executor {
        final ArrayDeque mTasks = new ArrayDeque();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {//串行执行
            mTasks.offer(new Runnable() {//将FutureTask加入到mTasks中,r就是前面传进来的mFuture,mFuture就是Futrue对象
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {//从 mTasks 取出 FutureTask任务
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

从上面代码可以看出,当调用SerialExecutor 的execute方法时,会将FutureTask加入到mTasks中。当任务执行完或者当前没有活动的任务时都会执行SerialExecutor里面的scheduleNext方法,它会从 mTasks 取出 FutureTask任务并交由 THREAD_POOL_EXECUTOR 处理。

加了synchronized关键字,所以SerialExecutor是串行执行的。可以看到执行了FutureTask的run方法,它最终会调
用WorkerRunnable的call方法。前面我们提到call方法最终会调用postResult方法将结果投递出去,postResult
方法的代码如下:

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

在postResult方法中会创建Message,将结果赋值给这个Message,通过getHandler方法得到Handler,并
通过这个Handler发送消息。getHandler方法如下所示:

	private Handler getHandler() {
        return mHandler;
    }

在getHandler方法中直接返回mHandler,在之前构造方法的时候判断mHandler==null时调用getMainHandler(),getMainHandler()代码如下所示:

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

在getMainHandler方法中创建了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;
            }
        }
    }

在接收到MESSAGE_POST_RESULT消息后会调用AsyncTask的finish方法,代码如下:

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

如果AsyncTask任务被取消了,则执行onCancelled方法,否则就调用onPostExecute方法。正是通过
onPostExecute 方法,我们才能够得到异步任务执行后的结果。

接着回头来看SerialExecutor,线程池SerialExecutor主要用来处理排队,将任务串行处理。在SerialExecutor中调用 scheduleNext 方法时,将任务交给 THREAD_POOL_EXECUTOR。它是一个线程池,代码如下:

	private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // We want at least 2 threads and at most 4 threads in the core pool,
    // preferring to have 1 less than the CPU count to avoid saturating
    // the CPU with background work
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));//根据CPU核心数计算核心线程数
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//根据CPU核心数计算最大线程数
    private static final int KEEP_ALIVE_SECONDS = 30;

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };

    private static final BlockingQueue sPoolWorkQueue =
            new LinkedBlockingQueue(128);//阻塞队列

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR;

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

THREAD_POOL_EXECUTOR 指的就是 threadPoolExecutor,它采用的阻塞队列仍旧是LinkedBlockingQueue,容量为128。其核心线程和线程池允许创建的最大线程数都是由CPU的核心数来计算出来的。

如果想要使用并行的线程处理,可以使用如下的代码:
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
也可以传入其他的线程池。

这里顺便提一下cancel方法,代码如下:

	public final boolean cancel(boolean mayInterruptIfRunning) {
        mCancelled.set(true);
        return mFuture.cancel(mayInterruptIfRunning);
    }

cancel方法调用了mFuture的cancel方法,其代码如下:

	public boolean cancel(boolean mayInterruptIfRunning) {
        if (!(state == NEW &&
              U.compareAndSwapInt(this, STATE, NEW,
                  mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
            return false;
        try {    // in case call to interrupt throws exception
            if (mayInterruptIfRunning) {
                try {
                    Thread t = runner;
                    if (t != null)
                        t.interrupt();//中断线程
                } finally { // final state
                    U.putOrderedInt(this, STATE, INTERRUPTED);
                }
            }
        } finally {
            finishCompletion();
        }
        return true;
    }

最终调用的是Thread的interrupt()方法。

原理就分析到这里吧。

你可能感兴趣的:(Android开发)