“AsyncTasks应该理想地用于短操作(最多几秒钟)。如果您需要让线程长时间运行,则强烈建议使用java.util.concurrent pacakge提供的各种API,如Executor、ThreadPoolExecutor和FutureTask。”
现在我的问题是:为什么?
doInBackground()
函数在UI线程之外运行,那么在这里有长时间运行的操作会带来什么危害呢?doInBackground()
函数在UI线程之外运行,那么在这里有长时间运行的操作会带来什么危害呢?这是一个非常好的问题,作为一名Android程序员,完全理解这个问题需要时间。确实AsyncTask有两个主要问题:
在RoboSpice Motivations应用程序(可在Google Play上获取)中,我们详细回答了这个问题。它将深入了解AsyncTasks、Loaders、它们的特点和缺点,并向您介绍网络请求的另一种替代方案:RoboSpice。 网络请求是Android中常见的需求,本质上是长时间运行的操作。 以下是该应用程序的摘录:
AsyncTasks不遵循Activity实例的生命周期。如果您在Activity中启动AsyncTask并旋转设备,则Activity将被销毁并创建一个新实例。但是AsyncTask不会死亡。它将继续存在直到完成。
而且,当它完成时,AsyncTask不会更新新Activity的UI。确实,它会更新以前的Activity实例,即不再显示的实例。如果您使用findViewById在Activity中检索视图,这可能会导致java.lang.IllegalArgumentException: View not attached to window manager类型的异常。
在您的活动内创建AsyncTasks作为内部类非常方便。由于当任务完成或正在进行时,AsyncTask将需要操作活动的视图,因此使用活动的内部类似乎很方便:内部类可以直接访问外部类的任何字段。
然而,这意味着内部类将保留对其外部类实例(即活动)的隐藏引用。
从长远来看,这会产生内存泄漏:如果AsyncTask持续时间很长,它将保持活动处于“活动”状态与之相反,Android想要摆脱它,因为它无法再显示。该活动不能被垃圾回收,这是Android保留设备资源的核心机制。
使用AsyncTasks进行长时间运行的操作确实是个非常糟糕的主意。然而,对于像更新视图一样的短暂操作,它们还是可以的。
我建议您下载RoboSpice Motivations应用程序,它真正深入地解释了这一点,并提供了不同的方法来执行某些后台操作的示例和演示。
为什么?
因为默认情况下,AsyncTask
使用一个你没有创建的线程池。不要占用你没有创建的线程池的资源,因为你不知道该线程池的要求是什么。如果该线程池的文档告诉你不要这样做,也不要占用你没有创建的线程池的资源,就像这里一样。
特别是从 Android 3.2 开始,默认情况下由 AsyncTask
使用的线程池(对于目标 SDK 版本设置为 13 或更高版本的应用程序)只有一个线程--如果你无限期地占用这个线程,那么你的其他任务将无法运行。
Service
,只需使用一个Thread
或者一个ThreadPoolExecutor
。 - CommonsWareTimerTask
是标准Java中的类,而不是Android中的。TimerTask
已经被大量弃用,现在更推荐使用ScheduledExecutorService
(尽管它的名字中带有"Executor",但它也是标准Java的一部分)。这两个类都与Android无关,所以如果你希望这些任务在后台运行,仍然需要一个服务。而且,你真的应该考虑使用Android中的AlarmManager
,这样就不需要一个一直挂着的服务来监视时钟滴答声了。 - CommonsWare