AsyncTask可能有的坑-Android

来源:互联网 发布:辐射4室内光源优化 编辑:程序博客网 时间:2024/05/16 12:05

  通过查阅官方文档发现,AsyncTask首次引入时,异步任务是在一个独立的线程中顺序地执行,也就是说一次只能执行一个任务,不能并行地执行,从1.6开始,AsyncTask中引入了线程池,支持同时执行5个异步任务,也就是说同时只能有5个线程运行,超过的线程只能等待,等待前面的线程某个执行完了才被调度和运行。换句话说,如果一个进程中的AsyncTask实例个数超过5个,那么假如前5个都运行很长时间的话,那么第6个只能等待机会了。这是AsyncTask的一个限制,而且对于2.3以前的版本无法解决。如果你的应用需要大量的后台线程去执行任务,那么你只能放弃使用AsyncTask,自己创建线程池来管理Thread,或者干脆不用线程池直接使用Thread也无妨。不得不说,虽然AsyncTask较Thread使用起来比较方便,但是它最多只能同时运行5个线程,这也大大局限了它的实力,你必须要小心的设计你的应用,错开使用AsyncTask的时间,尽力做到分时,或者保证数量不会大于5个,否则就可能遇到上面提到的问题。可能是Google意识到了AsyncTask的局限性了,从Android 3.0开始对AsyncTask的API做出了一些调整:每次只启动一个线程执行一个任务,完成之后再执行第二个任务,也就是相当于只有一个后台线程在执行所提交的任务,可以通过代码在不同sdk版本中执行的具体情况来验证官方文档的说法.

  习惯了参照官方文档和线程的代码,没有认真研读源码导致踩了AsyncTask的这个坑,如果知道使用executeOnExecutor方法,自己定义线程池就不会出现Task任务没有立即执行的情况,这再次印证了阅读android源码的重要性,最后具体的解决方式如下:

LinkedBlockingQueue<Runnable> blockingQueue = new LinkedBlockingQueue<Runnable>();ExecutorService exec = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, blockingQueue);new LoadTask().executeOnExecutor(1);

》使用Android 4.1之前的版本,使用AsyncTask前,先在UI线程中调用一次AsyncTask.init()方法;

Android有一个原则---单线程模型的原则:UI操作并不是线程安全的并且这些操作必须在UI线程中执行。

在单线程模型中始终要记住两条法则:
1. 不要阻塞UI线程
2. 确保只在UI线程中访问Android UI工具包

》为了正确的使用AsyncTask类,以下是几条必须遵守的准则:
1) Task的实例必须在UI thread中创建
2) execute方法必须在UI thread中调用
3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)这几个方法
4) 该task只能被执行一次,否则多次调用时将会出现异常
doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground 接 受的参数,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecute传入的参数。

  以上四点是我从网摘过来的,我觉得说的有道理,针对第4点,我有异议:即使多次调用,也不应该出现异常,因为AsyncTask类有对外公开的接口,cancel(true),isCancelled()。这两个方法,这两个方法配合使用就来控制AsyncTask可以手动退出。

再来说说AsyncTask坑人的地方,就是在Android3.0以后的版本,AsyncTask的执行方法分为2个了:

(1)execute() (2)executeOnExecutor()

如果用AsyncTask调用(1)的时候,就表示串行执行线程,如果这个Activity中有4个fragment,而且每个fragment都有一个AsyncTask,这样的话用(1)的话,就必须顺序执行,等一个执行完,第二个才执行。如果用方法(2),则可以串行执行,这个UI效果就很好了。线程池可以用系统的,也可以用我们自定义的线程池;

另外对系统默认线程池中执行线程数的一些说明,如下:

下面的5代表corePoolSize,10代表阻塞队列的长度,128代表maximumPoolSize1:如果线程池的数量小于5,则创建新的线程并执行2:如果线程数大于5且小于5+10(阻塞队列大小),则将第6~15的线程加入阻塞队列,待线程池中的5个正在运行的线程有某个结束后,取出阻塞队列的线程执行。3:如果线程数为16~128,则运行的线程数为num-104:如果线程数大于128,则舍弃。

0 0