作者博客
http://www.cherylgood.cn/
目录
1
前言
AsyncTask,相信你不会陌生,也许你很幸运,早已了解了AsyncTask这个家伙挖的坑,也许你已经被坑过了,也许你没坑了,然而还没有发觉!
本次笔者将带大家一起来看下AsyncTask这个坑是如何挖出来的。
啥也不说啦,我们先来段代码看看。
1、首先创建一个AsyncTask类
2、假设你这样运行
3、你觉得会发生什么呢?
2
AsyncTask知识补充
(如果你对AsyncTask已经很熟了,可以跳过该章节)
(不需要的的数据可以设置为Void哦)
3
AsyncTask使用注意事项
4
以日常使用为起点分析AsyncTask的源码
OK,假设你使用AsyncTask时都是使用execute方法来调用,那么我们就从他入手吧!
我们进入execute的方法体看下,里面做了什么呢?
我先我们看到一个@MainThread的注解。这是什么东东呢?我没用过呢。
其实它是google提供的一个注解,标注我们的这个方法必须在主线程中调用,如果不是的话,AS就会红色提示我们哦。
然后我们可以看到,execute里面其实是执行了executeOnExecutor方法,他传入了两个参数:
1、sDefaultExecutor(这是干什么的呢?)
2、params 从execute传递下来的可变参数。
OK,重点就是sDefaultExecutor了,从名字上看sDefaultExecutor是个磨人的执行器的意思,但我们是很较真的人,所以必须看下sDefaultExecutor是个什么东东,所以就逗逼逗逼的去找相关代码了。
OK,从其定义的地方可以看到,sDefaultExecutor是一个Executor类型的实例,通过SerialExecutor()获得。我们下看SerialExecutor()里面都做了什么?
从上面代码可以看到,里面有一个mTasks的数组队列。当我们调用Execute的时候就会在mTasks队列中插入一个runnable实例,也就是说,mTasks里面存放的是线程,可能你会很奇怪,首先这里public synchronized void execute(final Runnable r)传如了一个runnable,然后这里mTasks.offer(new Runnable() 又创建一个新的runnable入队列。
OK,更详细的分析我放到了代码中。
OK,我们继续回到executeOnExecutor方法。
小结:
通过上面代码,我们知道,在执行AsyncTask的execute方法时,我们的线程默认是放入一个ArrayQueue队列中串行的执行的。也就是sDefaultExecutor是一个串行的执行器,所以我们的AsyncTask默认是串行自行的。
OK,我们来进一步分析下AsyncTask的执行过程,首先我们看下AsyncTask的构造方法都做了什么。
①:创建一个WorkerRunnable,注意第二个泛型参数Result,这个就是我们继承AsyncTask时传递的第三个参数哦,然后里面看到调用了result = doInBackground(mParams);最终都会调用postResult(result);方法。
②:创建一个FutureTask的对象,mFuture就是我们前面executeOnExecutor方能发中最重调用exec.execute(mFuture);传入的参数哦,说明mFuture是个runnable类型的实例。然后把mWorker传入创建,说明runable执行的是mWorker里面的工作,yes,所以我们的doInBackground方法是在runable线程中执行的。
OK,我们之前只说了我们的代码是如何放入子线程中的,但是并没有看见启动子线程的代码啊?我们可以看奥,他最终都调用的postResult方法。
OK,可以看到,里面是通过我们熟悉的Handler来进行实现的哦。我们看他他传入了MESSAGE_POST_RESULT和AsyncTaskResult,this就是我们的AsyncTask了,后面应该是在handler中调用了AsyncTask的某个方法,我们看下getHandler()。
OK,里面是一个InternalHandler实例。而InternalHandler是这样的。
OK,里面看到了MESSAGE_POST_RESULT对应的是finish方法。也就是我们的AsyncTask的finish方法。
可以看到,里面最终会调用onCancelled(result);或者onPostExecute(result);
小结:
创建 AsyncTask是会创建mWorker和mFuture,mFuture是一个runable类型的对象,最终会在我们执行execute-》executeOnExecutor时,传入执行队列中等待执行。在传如前先调用了onPreExecute()方法,在mFuture被执行的时候,会回调mWorker的call方法,call方法里会调用doInBackground方法,获得doInBackground的执行结果后调用postResult方法,postResult内部通过handler切换线程,最终调用我们的finish方法,finish里面会调用onCancelled(result)或者onPostExecute(result);中的一个。这样我们的AsyncTask的一个关键流程就走完了。
5
我想让AsyncTask并行执行,可以么?
当然可以,我们前面分析了,串行还是并行,关键是执行器。因为默认传入的是sDefaultExecutor,sDefaultExecutor是个串行的执行器,所以我们传入一个并行的执行器,是不是就可以了呢?
我们可以看到AsyncTask也提供了一个THREAD_POOL_EXECUTOR,根据注解,使用它可以让execute 并行工作
/** * An {@link Executor} that can be used to execute tasks in parallel. */public static final Executor THREAD_POOL_EXECUTOR;
看到这里我有点郁闷了,前面在分析SerialExecutor是,里面不也是将runable让入THREAD_POOL_EXECUTOR中执行么?
SerialExecutor为什么是串行呢?虽然也是放入THREAD_POOL_EXECUTOR中,但是他是从队列中取出来放入的哦,而且一次只取出一个,执行完再取第二个。
6
总结
通过本次学习,我们了解了AsyncTask从创建到执行返回结果的工作流程,也明白了为什么默认时串行执行的。当然,改为并行也是非常简单的,你可以自己自定义执行器,自己来控制,但是一般都不需要的( ̄∇ ̄)。通过本次学习,相信在使用AsyncTask时,你会更加踏实。厚积而薄发!
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有