«

Android AsyncTask简要分析

时间:2024-3-2 19:36     作者:韩俊     分类: Android


在Android中实现异步任务机制有两种方式,Handler和AsyncTask。请参考Handler的简要分析,本文重点从源码角度分析AsyncTask的大致流程。
一个异步任务的执行一般包括以下几个步骤:
1.execute(Params… params),执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。
2.onPreExecute(),在execute(Params… params)被调用后立即执行,一般用来提高用户体验,显示加载进度条。
3.doInBackground(Params… params),在onPreExecute()完成后立即执行,一般在子线程中执行,用于执行较为耗时的操作。在执行过程中可以调用publishProgress(Progress… values)来更新进度信息。
4.onProgressUpdate(Progress… values),在调用publishProgress(Progress… values)时,此方法被执行,直接将进度信息更新到UI组件上。
5.onPostExecute(Result result),doInBackground(Params… params)执行完毕后,此方法将会被调用,同时子线程执行结果以参数的形式传过来,可以将结果显示到UI组件上。
6.onCancelled() 调用该方法在取消消息后进行一些操作。
从上面的简单介绍可以看出,以上方法的执行是有一定顺序的,那么它如何做到的呢?下面从源码角度进行分析!

1、首先当开发者调用execute(Params… params)时:

public abstract class AsyncTask<Params, Progress, Result> {
    private final **WorkerRunnable**<Params, Result> mWorker;
    private final **FutureTask**<Result> mFuture;
    private volatile Status mStatus = **Status.PENDING**;
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    public static final Executor **THREAD_POOL_EXECUTOR**
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);//线程池
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
            return **executeOnExecutor**(sDefaultExecutor, params);
        }
    public final AsyncTask<Params, Progress, Result> More ...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;//刚开始mStatus=Status.PENDING,执行至此改为Status.RUNNING
            **onPreExecute()**;//此处在主线程中执行一些操作,如显示进度条
            mWorker.mParams = params;
            **exec.execute(mFuture)**;
            return this;
        }
}

执行execute,最终是执行executeOnExecutor(sDefaultExecutor, params),该方法是是重点。
(1)该方法修改了mStatus的值,由此可以看出,异步任务只能执行一次,再次进入该方法由于mStatus = Status.RUNNING会进入到switch中而抛出异常。
(2)传递的参数为sDefaultExecutor。有上面定义可知是实例化了SerialExecutor类,调用了exec.execute(mFuture):

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

execute方法最终都会调用scheduleNext()方法,最终是执行THREAD_POOL_EXECUTOR.execute(mActive);有上面定义可知,THREAD_POOL_EXECUTOR是一个线程池,所以exec.execute(mFuture)的实质是从线程池中取出线程来执行。只不过在调用scheduleNext()方法之前,调用了mTasks.offer()方法,该方法的作用是将Runnable对象存放到线程队列最后的位置中。

 public class ArrayDeque<E> extends AbstractCollection<E>
                           implements Deque<E>, Cloneable, Serializable
 {
    public boolean offer(E e) {
        return offerLast(e);//由字面意思也可知道是将e添加到队列末尾
    }
}

这样就可以按照队列存放的顺序依次取出Runnable来执行了。
取出Runnable后执行run方法,该方法调用了r.run();此处的r为传入的mFuture。这个类的定义在开发者实例化AsyncTask时:

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

在实例化AsyncTask时,也实例化了mWorker和mFuture,调用r.run(),实际上是调用mFuture.run();

public class FutureTask<V> implements RunnableFuture<V> {
  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()**;//此处的c即为传入的mWorker
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            runner = null;
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }
}

注意加粗部分,即调用了mWorker.call()方法。有上面代码可知call方法最终调用postResult(doInBackground(mParams))方法。里面的doInBackground即为开发者重写的doInBackground方法。而postResult方法:

private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
}
private static Handler getHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new **InternalHandler**();
            }
            return sHandler;
        }
}

该方法实质上是通过handler发送一个MESSAGE_POST_RESULT消息。该handler是InternalHandler的一个实例。

private static class InternalHandler extends Handler {
        public InternalHandler() {
            super(Looper.getMainLooper());//该方法说明AsyncTask一定是定义在主线程中,否则一般线程是不允许调用getMainLooper()方法的。
        }
        @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);//此处调用开发者自定义的onProgressUpdate方法更新进度条
                    break;
            }
        }
    }
private void finish(Result result) {
        if (isCancelled()) {
            **onCancelled**(result);
        } else {
            **onPostExecute**(result);
        }
        mStatus = Status.FINISHED;
}

此处finish方法有两个作用,如果开发者没有在这之前取消消息,即调用onPostExecute(result)方法。
而如果开发者取消了消息,即开发者调用了cancel(true)方法:

 public final boolean cancel(boolean mayInterruptIfRunning) {
        mCancelled.set(true);//此处设置为true后,上面的isCancelled()方法返回值为true
        return mFuture.cancel(mayInterruptIfRunning);
    }

该方法里面调用了mFuture.cancel(mayInterruptIfRunning):

 public boolean cancel(boolean mayInterruptIfRunning) {
            ……
        **finishCompletion()**;
        return true;
}
   private void finishCompletion() {
    ……
    **done()**;
 }

该方法调用finishCompletion()方法,最后调用done()方法,而在mFutuer.done()里面,调用了postResultIfNotInvoked(get())方法:

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

该方法最终还是调用了postResult方法,发送一个MESSAGE_POST_RESULT消息,此时handler再次调用finish方法,此时isCancelled()为为true,调用开发者重写的onCancelled()方法。
至此,AsyncTask中的重要方法都通过追踪代码的形式对他们的执行流程有了一个大致的认识。总结一下:
(1)AsyncTask主要是通过Handler+ThreadPoolExecutor实现。
(2)AsyncTask必须定义在主线程中。onPreExecute(),onProgressUpdate(Progress… values),onPostExecute(Result result),onCancelled()方法都是工作在线程中,doInBackground(Params… params)工作在子线程中,而不同线程之间的通信主要通过handler来实现。
(3)AsyncTask中线程池分为THREAD_POOL_EXECUTOR( 异步线程池) SERIAL_EXECUTOR(同步线程池),默认为同步线程池,通过定义看以看出: private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;但是从本质来看,通过上面的代码跟踪,我们看以知道sDefaultExecutor最终还是调用了THREAD_POOL_EXECUTOR的execute方法。只是在调用之前通过一个队列将任务有序的存放起来,保证任务的顺序执行。

        <p>版权声明:本文为博主原创文章,未经博主允许不得转载。</p>

标签: android

热门推荐