AsyncTask的版本兼容性与target sdk version

最近发现了一个奇怪的问题,一处很久前写的代码,通过AsyncTask的doInBackground进行后台处理,突然间不管用了,就是说doInBackground没有被执行。同事查询SVN,发现相关代码没有过任何更改,经过很久的检查,发现只有在Manifest中有一处很小的改动,就是添加了targetSDKVersion。将这个属性去掉,就没有问题了。

 

通过对源码和google group以及stackoverflow的各种查找和测试,发现google挖了两个坑,不幸的是,我们跳了。

 

第一个坑:AsyncTask在Android各个版本中可以算是频繁修改了,比较各版本代码发现,修改过多次,而且这种修改会导致很大的差别。最坑的修改是在Android 4.0开始的,AsyncTask的中execute方法的实现在4.0以前是采用Thread pool executor,各个版本对线程池中的可并行线程数限制不同,但毕竟多个Task是多线程并行。而在4.0开始,改为用serial executor,就是说同一时间只能有一个线程运行,其他线程必须等待该线程完成之后才能开始执行,因此就变成了串行的worker thread。

 

第二个坑:targetSDKVersion,这个属性其实很多开发者都没有注意到,Google在官方文档中的解释又十分复杂,导致它出了问题就很难定位。总的来说,这个属性是Google为了进行兼容性检查来设置的,有一些API,例如AsyncTask这种,会根据它的设置来选择执行方式。如果targetSDKVersion设置成了4.0,那么系统就认为你的应用在4.0版本上有了足够的测试,不会有问题,那么会选择4.0的各种新特性,就是说用serial executor来实现AsyncTask。如果不加入targetSDKVersion,默认这个值会等于minSDKVersion,这时候系统认为你没有在4.0版本上测试,为了防止出问题,在4.0手机上会采用Thread pool executor来实现AsyncTask。因此就导致了我们之前的问题。

 

Google对AsyncTask增加了一个方法,executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, ....);通过这个方法可以强制系统用Thread pool executor实现。但是需要API level 11,调用也会很麻烦。还是要注意逻辑,对长时间占用背景线程的操作避免用AsyncTask,或者自己写一个AsyncTask更靠谱一些。

你可能感兴趣的:(线程,android,AsyncTask)