AsyncTask的优缺点

继上篇简单介绍AsyncTask之后,本片开始介绍下AsyncTask的优缺点。
(注:本人所写文章仅作为自己学习使用)

AsyncTask的优点:

封装了Thread和Handler给用户使用,操作比较简单。用户需要使用时,仅需继承AsyncTask,并重写其中的doInBackground方法就可以,若是希望子线程的执行结果反馈到UI线程上,则将onPreExecute(告知UI线程,子线程开始执行)和onPostExectute(将子线程执行的结果反馈给UI线程)和onProgressUpdate(可以实时的将子线程的执行过程反馈给UI,一般是使用进度条)重写就可以。

AsyncTask的缺点

  1. 旋转屏幕
    使用AsyncTask的最初目的是希望为UI线程开启一个后台线程,用于与之进行交互。因为常见对AsyncTask的使用是去执行一个耗时操作,并在结束后(AsyncTask.onPostExecute())更新UI。但是旋转屏幕,当前的Activity会被销毁然后重建,Activity重启后,此时AsyncTask对Actvity的引用是invalid,因为他指向的还是前一个没有转屏前的Activity,并不是重建后的Activity,So onPostExecute对重建后的Activity是没有意义的。这点尤其是在将AsyncTask作为Activity的内部类,AsyncTask会隐式应用当前Activity的时候给人制造困惑。
    避免该问题的一个常规做法是,保留对AsyncTask的引用,该引用在配置更改之间持续,在重新启动时更新目标Activity。
  2. 生命周期
    AsyncTask的生命周期和Activity的生命周期不同步。不管Activity的生命周期是否已经结束(即使是application已经退出),AsyncTask会一直执行到doInBackground结束,之后,会选择下面的某一种方式继续执行:
    a) 如果cancel(boolean)调用了,则执行onCancelled(Result)方法
    b) 如果cancel(boolean)没有调用,则执行onPostExecute(Result)方法
    只有一种提早finish AsyncTask方式:通过AsyncTask.cancel()来取消AsyncTask任务。也就是说你需要手动取消AsyncTask,否则你会冒着不必要的后台任务拖垮你的应用程序的风险,或者内存泄露。当你明确不在需要AsyncTask的时候,请确保手动取消该AsyncTask,以免后续在执行APP的过程中出现别的问题。
  3. Cancelling AsyncTask
    假设使用AsyncTask来执行一个查询操作。用户可能会在查询的过程中修改参数,此时你需要调用AsyncTask.cancel()来结束当前的任务,然后发起一个新的AsyncTask来执行用户修改完参数的查询。这种方法看起来是ok的,但是当check log的时候,我们会发现当前所有的AsyncTask都在运行,cancel方法并没有任何的意义,就算mayInterruptIfRunning这个参数为True。
    Why?
    问题发生在AsyncTask.cancel()这个方法上,该方法并不会不计后果的杀死后台线程,它所有的操作唯有将AsyncTask的状态置为“canceled”,然后依赖用户去检查AsyncTask是否被cancel掉了,如果用户发现AsyncTask已经被cancel了,然后才可以终止操作(这句话不是很理解)。对于参数mayInterruptIfRunning,它只是给后台正在运行的线程发了一个interrupt(),在后台线程不可中断的情况下,它根本不会停止线程。
    有两种简单的方案可以解决大多数上面的问题:
    在耗时较长的任务中,定期检查AsyncTask.isCancelled(),或者保持线程可中断。
    无论哪种方式,当调用AsyncTask.isCancelled()时,这些方法都会阻止您的任务执行比必要时间更长的时间。

但是,这个建议并不总是有效的——如果您调用了一个不可间断且耗时较长的方法(比如BitmapFactory.decodeStream())呢?我在这种情况下所获得的唯一成功就是创建了一个导致抛出异常的情况(在本例中,过早地关闭了BitmapFactory使用的流)。这意味着单独的取消不能解决这个问题——需要外部干预

  1. 并发任务数量受限
    AsyncTask任务运行于线程池的。一般线程池的大小是固定的,这就导致AsyncTask可以并发的任务也是固定的。Android 1.5规定AsyncTask仅允许存放128个并发任务,同一时间只有10个任务可被同时处理(这10个任务以队列的形式存放)。也就是说如果你在完成138个任务之前排队,你的应用程序就会崩溃。大多数情况下,当人们使用AsyncTask从网络上加载Bitmaps时,会有这个问题。

当你发现自己面临这种限制的时候,应该考虑下你代码的设计,为什么会有这么多需要后台执行的任务了。或者另一种可以选择的方式为,为当前的任务创建一个较智能的队列,不要一次性并发执行那么多的代码。你要是实在是接受不了,可以重新定义AsyncTask的线程池大小。

总结:

由于AsyncTask的生命周期和Activity的生命周期不同步,并不会随着Activity的销毁而销毁,所以有时候会造成Activity的内存无法销毁,造成内存泄露,此其一。

也是因为AsyncTask的生命周期并不随着Activity的的销毁而销毁,导致在转屏的时候,转屏前AsyncTask的执行内容并没有传给转屏后的Activity,相当于AsyncTask的执行结果白白浪费了,此其二。

AsyncTask的任务运行于线程池,线程池的大小固定,要是想要执行的任务超出线程池规定的大小,会造成Crash,而且在Android1.5之后规定,不建议并发执行任务,此其三。

其他的,等后续继续补上。

参考:
https://blog.danlew.net/2014/06/21/the-hidden-pitfalls-of-asynctask/

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值