我该在我的应用程序中使用AsyncTask还是IntentService?

54
我一直在研究Android的网络连接,并注意到有不同的处理方式,如AsyncTaskIntentService。然而,我仍然不确定该使用哪种方法。我的应用程序基本上是一个带有Google Maps的位置/路径查找器。我的互联网连接将用于在地图半径内查找最近的路径。因此,每当用户移动或滑动地图到新位置时,它将更新最近的路径。它还将添加新路径,并允许用户评价路径。
对于这个问题,AsyncTask是否足够,或者我应该使用IntentService
8个回答

59
They can be used very differently for different purposes. AsyncTask是一个方便的线程工具,可以根据需要不断告知用户某些信息或定期在主线程上执行操作。它提供了很多细粒度控制,并且由于其性质,在Activity中非常易于使用,而IntentService通常需要使用BroadcastReceiverIBinder框架。请注意保留HTML标签。

IntentService可以像AsyncTask一样使用,但它的目的是用于后台下载、上传或其他不需要用户交互或主线程的阻塞操作。例如,如果您想下载和缓存地图,您可能希望调用一个IntentService,这样用户就不必在应用程序中查看它进行下载。同样,如果您要向服务器发送数据,IntentService在这方面非常有帮助,因为您可以启动并忘记。用户可以在您的应用程序中输入评论,然后按“发送”。 “发送”将启动IntentService,该服务获取评论并在后台线程上将其发送到您的服务器。用户可以立即离开应用程序,评论最终仍将到达您的服务器(当然,假设没有错误)。另一方面,在您的Activity中使用AsyncTask进行此操作时,系统可能会在交换过程中杀死您的进程,这可能会导致交换成功或失败。

通常来说,它们都不适用于长时间运行的应用程序。它们适用于短暂的一次性操作。虽然它们可以用于永久或长时间运行的操作,但并不推荐这样做。


4
长时间运行的操作应该使用什么? - roiberg
2
如果Java线程阻塞,可以使用通用的Java线程。根据需要,可以将其放置在Activity或Service中。使用生命周期方法控制生命周期,以确保在不应运行时不运行。 - DeeV
“IntentService通常需要操作BroadcastReceiver框架。”不,它不需要。请参见@Joe Malin的答案:https://dev59.com/RmUp5IYBdhLWcg3wmYct#15168625? - Jim G.
2
这是与使用回调函数的Asynctask进行比较的。您不必为任何事情使用BroadcastReceivers,但如果希望它向Activity报告回来,则可以采用此方法。另一种方法是绑定服务,因为它本质上是一个普通的Service。 - DeeV
可以使用IntentService来进行长时间运行的操作。我(正确地)将其用于永久性操作。 - ban-geoengineering
显示剩余3条评论

52

如果您正在进行与活动紧密相关的短期重复任务,建议使用AsyncTask。而IntentService更适用于应在后台独立运行的计划任务(无论是否重复)。


3
假设你在你的应用程序中保存了某个区域的步道(类似于“收藏夹”或类似功能)。如果你想让它们保持最新状态,那么只需设置一个每天运行并检查这些地区变化的“IntentService”。 - ebarrenechea
3
基本上,尽管我相当确定它们使用推送通知,但那是完全不同的东西。这就像带有IMAP / POP3的电子邮件应用程序每x分钟检查电子邮件一样。 - ebarrenechea
1
“IntentService更适合于定期或非定期在后台独立运行的任务。但是,如果您希望即使应用程序关闭也能运行某些内容,则需要使用Service而不是IntentService。” - Kanwal Sarwara
我在一些应用程序中这样做:当应用程序启动时,如果需要更新本地数据(例如上次更新时间、WIFI可用性等),我会启动一个IntentService。应用程序始终显示本地存储的内容。当有新数据可用时,我使用LocalBroadcastManager通知应用程序并刷新其视图(大多数情况下调用adapter的notifyDataSetChanged)。在这种情况下,IntentService比AsyncTask更好。无论何时有数据准备好,当前活动的任何活动都将得到通知,并可以选择对新数据进行操作或不进行操作。 - Glenn Bech
@Sarwara,请问如何获取活动结果,比如我发送了一条消息,我需要知道这条消息是否已经被送达? - Paul Okeke
显示剩余5条评论

22

AsyncTask 不太适合配置更改或其他重新启动 Activity 的情况。

IntentService 适用于应该始终可用的某些内容,无论其工作需要多长时间。在大多数情况下,我更喜欢 IntentService,因为 AsyncTask 更依赖于 Activity 状态。

一些注意事项:

  • AsyncTask 最适合快速任务,应立即返回到 UI,但它可用于各种情况。
  • “定期在主线程上执行操作”的说法不太清楚。AsyncTask 会生成一个新的后台线程,与主线程不同,并在新线程上执行其工作。因此名为 AsyncTask。
  • IntentService 不需要“操作” BroadcastReceiver 框架。您只需发送本地广播 Intent 并在 Activity 中检测它即可。这是否比 AsyncTask 更难做到,我不知道。
  • IntentService 旨在执行长时间运行的任务,它会在后台执行。
  • AsyncTaskLoader 可以使用,但它是 CursorLoader 等的基类。如果要在用户移动到新位置时刷新“附近”路径,则 IntentService 可能更好。

在尝试更新位置之前,请不要忘记检查连接性。


8
AsyncTasks非常紧密地绑定在Activity上,如果你离开创建AsyncTask的Activity,它往往会导致窗口泄漏错误。但是,它们非常适合显示ProgressBar,因为你可以快速更新进度百分比。
IntentServices更加清洁和安全。对于初学者来说,实现它们可能更加困难,但是一旦你学会了如何启动和处理它们,你可能就再也不会回到AsyncTasks了!
IntentServices还允许您在应用程序中进行更模块化的设计。我通常为所有我的IntentServices创建一个单独的类,但是对于AsyncTasks,我将它们创建为Activity内部类。如果我要从Activity中分离出一个AsyncTask,我必须在AsyncTask构造函数中传递Activity Context和View对象,这可能会很混乱。

为了解决混乱的问题,你可以在你的AsyncTask类中添加一个内部接口。该接口将包含回调方法,由活动来实现。 - ban-geoengineering

6
如上所述,AsyncTask将解决您的问题。但要记住,AsyncTask有一个重要的弱点:它无法很好地处理Activity的“刷新”(例如在旋转期间)。如果用户在您的AsyncTask仍在加载内容时旋转手机,则可能会出现问题。如果这确实是对您造成问题的情况,我建议使用AsyncTaskLoaderhttp://developer.android.com/reference/android/content/AsyncTaskLoader.html

4

AsyncTaskIntentService有许多相同之处:

  • 可以在工作线程中执行任务
  • 可以在后台运行
  • 即使启动它的活动被销毁,也能一直运行直到任务完成
  • 可以在任务运行期间或任务完成后通知更新UI
    • 对于AsyncTask,我们通常使用onProgressUpdateonPostExecute或者如果需要的话可以使用BroadcastReceiver
    • 对于IntentService,我们使用BroadcastReceiver

不同之处

1) 在运行时发送任务或在运行完成后发送任务

例如,我们有一个任务是:根据fileName从服务器上下载文件。

使用AsyncTask

如果我们有一个AsyncTask实例,在执行下载文件A期间,我们无法执行下载文件B的AsyncTask(因为会出现java.lang.IllegalStateException: Cannot execute task: the task is already running.)。并且在下载文件A完成后,我们也不能执行下载文件B的AsyncTask(因为会出现java.lang.IllegalStateException: Cannot execute task: the task has already been executed (a task can be executed only once))。
要在下载文件A期间或之后下载文件B,我们需要创建新的AsyncTask实例。
=> 要下载文件A和文件B,我们需要2个AsyncTask实例 => 创建了2个工作线程。

使用IntentService

在下载文件A期间,我们可以发送意图来下载文件B => 在下载文件A完成后,它将自动开始下载文件B => 不需要新的实例,也不需要新的工作线程。

如果我们在下载文件A完成后发送意图来下载文件B呢?下载文件A完成后,IntentService将被销毁(因为没有更多任务了)。因此,在开始下载文件B时,会创建一个新的Service实例,但不会创建新的线程(服务仅使用在IntentSevice构造函数中定义的名称的1个工作线程)。

2) 实现AsyncTask比实现IntentService更容易

使用
我们将看到AsyncTaskIntentService有许多相同之处,因此在大多数情况下,我们可以使用AsyncTaskIntentService。然而,

  • 我经常使用AsyncTask来处理在一个Activity中开始、结束和与UI交互的某些任务。
  • 我经常使用IntentService来处理可以从任何Activity开始/结束并与UI交互或不与UI交互的某些任务。

这个答案是基于我的测试。如果我有错误,请纠正我。希望它能帮助到你。


0

-1

我同意@DeeV和@ebarrenechea的看法,即你应该将Intent Service用于与Activity不紧密绑定的任务,例如将一些数据上传到服务器或从服务器存储数据到数据库。

但是,从Android 3.0开始,引入了Loaders API,它应该替换AsyncTask。因此,例如加载列表以在Activity中显示更好使用Loader,它被设计为处理所有配置更改和Activity生命周期。

Vogella loader tutorial


你确定加载器应该用于服务器工作吗?我以前从未听说过这个,并且在你提供的文档或教程中也没有看到任何建议如此做。 - ban-geoengineering

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接