AsyncTask源码分析

AsyncTask的使用介绍:

AsyncTask从Build.VERSION_CODES#HONEYCOMB 开始默认的执行方式是单个线程串行执行任务,而不是多个线程并发执行,如果要多个线程并发执行任务,可以调用executeOnExecutor()方法,并传入其自带的THREAD_POOL_EXECUTOR字段,该类异步操作适合较短的耗时操作,官方例子如下:

/**泛型分别是代表oInBackgroud(),onProgressUpdate(),onPostExecute()三个方法的参数类型*/
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;
     }
    //在UI线程执行,以更新进度条
     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }
    //doInBackground执行完后,结果会以参数形式传入,并调用其方法
     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }

AsyncTask的源码剖析:

AsyncTask的构造方法:

/**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */    
    public AsyncTask() {
        //任务对象
        mWorker = new WorkerRunnable<Params, Result>() {
            //AsyncTask对象调用execute()时候,实际会来到这里开始执行耗时任务
            public Result call() throws Exception {
                //任务被执行的标记,任务如果被执行,则为true
                mTaskInvoked.set(true);
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //执行耗时的后台任务
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                return postResult(result);
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            //上面的mWorker对象的call()执行完时候会执行该方法
            @Override
            protected void done() {
                try {
                    //当任务没有被call方法执行时,也会调用postResult方法间接运行onPostExecute()方法
                    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对象,然后再封装成FutureTask对象,那么WorkerRunnable对象又是什么呢?它是一个实现Callable的子类,代码如下:

 private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
         //传给doInBackgroud的参数值
        Params[] mParams;
    }

关于FutureTask类是什么东西,可以参考下面我之前写过关于线程一篇博客,那里有讲到它的用法:
http://blog.csdn.net/xuguoli_beyondboy/article/details/44180003
AsyncTask.execute()的方法分析:

//一定要在主线程调用,并且默认是单个线程串行执行任务
 @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

//调用execute()实际上在调用executeOnExecutor()方法,并且只能调用一次
@MainThread
    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();
        //设置传给doInBackgroud的参数
        mWorker.mParams = params;
        //执行任务
        exec.execute(mFuture);
        return this;
    }

从源码分析可以看出AsyncTask.execute()一定要在主线程执行并且只能执行一次,然后再通过调用exec.execute(mFuture) 执行任务,该方法一旦调用,会自动执行mFuture里面的WorkRunnable的call()方法,这就意味着doInBackgroud()方法也将在调用exec.execute(mFuture)方法后执行,而exec 是在由变量sDefaultExecutor传入,而sDefaultExecutor又是在初始时候赋值的,看下面源码分析:

//串行执行任务的执行器
 public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
//初始化线程执行器
 private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
 //获取CPU核数
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE = 1;
    //线程工厂
    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<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128);
//执行任务线程池
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
//自定义串行执行任务的执行器
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();
                    }
                }
            });
            //第一次执行该execute()的方法时,会执行这里
            if (mActive == null) {
                scheduleNext();
            }
        }
        /**同步执行下一个任务*/
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

从源码可以知道有两个细节问题,第一个就是任务是通过队列来管理的,这也说明默认AsyncTask执行任务方式是采用先进先出的方式来逐一执行的,第二个就是AsyncTask的所有任务实际上是由THREAD_POOL_EXECUTOR这个线程池来执行的,然而其存储方式是链表阻塞队列,并且初始化容量是128 Runnable对象,这也意味着,如果用AsyncTask采用THREAD_POOL_EXECUTOR这个线程并发执行任务,则任务对象存储不能超过128,但串行执行任务就不用考虑其问题,因为其采用同步方式,保证任何时刻只有一个任务在THREAD_POOL_EXECUTOR这个线程池中。
AsyncTask的onPostExecute()和onProgressUpdate()方法调用时刻:
从上面AsyncTask()构造方法,我们知道call()方法里面调用了postResult(result)方法,done()方法里又执行了postResultIfNotInvoked()方法,那么这两个方法做了什么呢?看下面源码分析:

//存储异步任务得到的结果信息类
private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }
/**结果传送给handler处理*/
    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
/**如果任务没有被call()执行,也会调用postResult()方法,间接执行onPostExecute()方法*/
    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }
@WorkerThread
    /**更新进度条*/
    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }

源码那里可以知道,更新UI操作是交给了handler去处理,那么handler是如何处理呢?看下面源码分析:

//获得handler
private static Handler getHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler();
            }
            return sHandler;
        }
    }
 //定义静态内部handler以避免内存泄漏
private static class InternalHandler extends Handler {
        public InternalHandler() {
            super(Looper.getMainLooper());
        }

        @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
                    //里面会执行onPostExecute()方法
                    result.mTask.finish(result.mData[0]);
                    break;
                /**更新进度条*/
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }
/**后台任务完成后*/
    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            //执行onPostExecute()方法
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

从源码分析,可以看出ononProgressUpdate()和onPostExecute()方法都是在handler当中执行,故可以更新UI操作。
AsyncTask的取消(cancel()方法)任务分析:

/**取消任务执行*/
    public final boolean cancel(boolean mayInterruptIfRunning) {
        //取消后续的任务执行
        mCancelled.set(true);
        //是否当断当前任务执行
        return mFuture.cancel(mayInterruptIfRunning);
    }
public final boolean isCancelled() {
        return mCancelled.get();
    }

再结合上面的finish()源码,我们知道一旦调用了cancel()方法,那么后面(包括当前正在执行的任务)的任务,其onPostExecute()方法将不会被执行,而如果cancel()传入了true,那么当前执行的任务会被打断,这也意味着doInBackgroud()可能没有完成就被打断,而传入false时候,则会将当前执行任务中的doInBackgroud()方法执行完。
AsyncTask的总结:
综合上面的所有分析知道,AsyncTask.execute()实际上是先通过executeOnExecutor()方法调用了onPreExecute()方法,然后SerialExecutor.execute()以数组队列的方式去存储任务(默认单个线程串行执行任务时候),最后通过THREAD_POOL_EXECUTOR线程池调用execute()去执行真正的任务,一旦任务开始启动执行就会执行WorkRunnable中的call方法,而call又会执行doInBackgroud()方法执行耗时操作,如果里面有publishProgress()方法将会通过主线程handler的方式发送消息,去调用onProgressUpdate()方法更新进度条,当doInBackgroud()方法执行完后,会通过调用postResult()方法发送消息,以让主线程handler通过调用finshed()方法里面的onPostExecute()去更新UI或处理结果。如果该任务没有被执行,则也会通过postResultIfNotInvoked()方法调用postResult()方法,从而间接执行onPostExecute()方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值