安卓:AsyncTask与Service的区别

140
为什么我发现大多数问题的答案中都提到了 AsyncTask 和 Loaders,但没有提到 Services?是因为 Services 不太熟知,还是已被弃用或存在一些不好的属性或其他原因?它们之间有什么区别?
(顺便说一句,我知道有其他关于这个问题的帖子,但没有一个清晰地说明如何轻松决定在实际问题中使用哪种方法。)
6个回答

275
在某些情况下,可以使用AsyncTaskService来完成相同的任务,但通常其中一个更适合该任务。 AsyncTask用于一次性耗时任务,这些任务不能在UI线程上运行。常见示例是按下按钮时获取/处理数据。 Service设计为在后台持续运行。在上面的示例中,当按下按钮时获取数据,您可以启动服务,让其获取数据,然后停止服务,但这是低效的。使用AsyncTask会更快,它只运行一次,返回数据,然后就完成了。
如果需要在后台持续执行某些任务,则Service是最好的选择。这包括播放音乐、不断检查新数据等示例。
此外,正如Sherif所说,服务并不一定在UI线程上运行。
总的来说,Service适用于希望在应用程序的Activity未打开时运行代码的情况。而AsyncTask旨在使在UI线程之外执行代码变得非常简单。

2
有趣的是,在2010年Google I/O的演讲中(http://www.youtube.com/watch?v=xHXn3Kg2IQE),演讲者提供了从REST API获取数据的三种不同方法,其中第一种使用了服务。虽然我不是Android专家,但我也认为Computerish所说的基本上是正确的。 - wuliwong
10
最后一段的意思是:“当您想要在应用程序的活动未打开时运行代码时,可以使用服务。这也适用于AsyncTask或后台线程。例如,当您在活动中按下返回键或调用finish()方法并且活动不可见时,但是您的后台线程仍在执行,直到您终止应用程序进程(例如通过从最近任务中切换)。我已经在4.4.2的Google Nexus AOSP grouper上进行了验证。” - Shirish Herwade
10
然而,如果启动AsyncTask的Activity在AsyncTask仍在运行并需要在完成后更新UI时被杀死,则可能会变得棘手(因为Activity已经被销毁)。为什么不使用IntentService呢?据我所知,你不需要手动停止IntentService,因为它在完成任务后就会自动结束。 - AgentKnopf
3
如果我理解得没错的话,您可以在Activity/Fragment中使用BroadcastReceiver,在IntentService中完成后只需触发一次广播即可。由于您可以在Activity/Fragment重新创建时重新注册广播,因此这样应该已经可以满足您的需求了。另一个选择是使用EventBus来更新UI(尽管我个人会尽量避免使用它,因为我认为这会使代码更难以理解)。 - AgentKnopf
@AgentKnopf:好的,我没意识到你在谈论一个活动/片段再次被创建的情况。这很有道理。 - LarsH
显示剩余2条评论

57

服务是完全不同的:服务不是线程

你的活动(Activity)绑定到一个服务(Service),而服务(Service)包含一些函数,在被调用时会阻塞调用线程。您的服务可能用于将温度从摄氏度转换为华氏度。任何绑定的活动都可以获得此服务。


然而,AsyncTask是在后台执行一些工作的线程(Thread),同时具有将结果返回给调用线程的能力。

只是个想法:一个服务可以拥有一个AsyncTask对象!


2
服务被描述为在后台运行,即使您的应用程序关闭也会继续运行。AsyncTask也用于在后台执行某些操作。你知道我的意思吗? - erikbstack
1
是的,但服务可能正在执行某些操作,它们是一个持久的对象。 - Sherif elKhatib
一个服务可能有一个AsyncTask对象!感谢指出这一点。但是这是一个好主意吗?你会推荐这样做吗?还是在服务中使用更基本的线程技术会更好? - RenniePet
你的 Activity 绑定到服务并不是必须的。 - JacksOnF1re
@JacksOnF1re 我知道这就像我刚开始编程时一样 :p 但是“您的活动绑定到服务”是一个真实的陈述。我也可以绑定到此服务。冰箱也可以绑定。这并不使该语句无效...无论如何,开个玩笑。 - Sherif elKhatib

7

Service是Android框架的组成部分之一,不需要UI执行。这意味着即使应用程序未被用户主动使用,也可以使用服务来执行某些操作。这并不意味着服务将在单独的线程中运行,而是在主线程中运行,当需要在单独的线程中执行操作时,可以在单独的线程中执行。

AsyncTask则用于在单独的线程上执行阻塞UI任务。它就像创建一个新线程,并在处理创建和维护线程及发送结果到主线程的所有任务时执行任务的方式一样由AsyncTask处理。 示例用途包括在后台播放音乐,与服务器同步数据等无需用户交互的操作以及从服务器提取数据,CRUD操作等。


你能否说明一下为什么认为你的回答对这个问题有所补充? - erikbstack
2
其他答案对于初学者来说要么太简短,要么太复杂难以理解。因此,我用简单的词语和例子精确地回答了问题。 - arjun

6

服务异步任务几乎是在做同样的事情,几乎。使用服务或异步任务取决于您的要求。

例如,如果您想要在从服务器加载数据到列表视图后按下某个按钮或更改屏幕,最好使用异步任务。它与主UI线程并行运行(在后台运行)。对于运行异步任务的活动或应用程序,应该在主UI线程上。退出应用程序后没有异步任务。

但服务不是这样的,一旦启动服务,它可以在您退出应用程序后继续运行,除非您停止服务。就像我说的那样,这取决于您的要求。如果您想要持续检查数据接收或检查网络状态,最好使用服务。

愉快的编码。


1
嗨,Ashana,我可以问一下为什么你会在已经有答案的问题中提供这个答案吗?你对现有的标记答案不满意吗?还是你试图通过回答所有你想说的问题来建立一个SO档案?或者完全不同的原因?我无法理解,但最近我经常看到这种模式。 - erikbstack
3
我知道答案已经给出了,如果我在这里提供正确答案或我的观点,对此不应该有太大问题,因为你不是唯一一个在寻找同样问题答案的人。如果有人难以理解以上答案中的解决方案,他/她可以向下滚动查找适合自己的答案,易于理解的答案。就这些了,感谢你的评论,我不是编程方面的天才或专家,只是想帮助其他人,尽力教授我已知的知识 :) - Ashana.Jackol

1

将一个本地、进程内、基类服务✱与AsyncTask进行比较:

✱(本答案不涉及导出的服务或在与客户端不同进程中运行的任何服务,因为期望的用例与AsyncTask大不相同。此外,出于简洁起见,某些特定的Service子类(例如IntentServiceJobService)的性质将在此处被忽略。)

进程生命周期

Service表示对操作系统的"应用程序希望执行长时间运行操作而不与用户进行交互" [ref]。

当您运行一个Service时,Android会理解您不希望该进程被杀死。同样的情况也适用于当您有一个Activity在屏幕上显示时,并且尤其适用于当您运行一个前台服务时。(当所有的应用组件都消失时,Android会认为:“哦,现在是一个好时机来杀掉这个应用程序,以便我可以释放资源”)。
此外,根据Service.onCreate()的最后返回值,Android可以尝试“恢复”由于资源压力而被杀死的应用程序/服务[ref]。 AsyncTasks并不会做任何这些事情。无论您有多少后台线程正在运行,或者它们正在努力工作的程度如何:Android都不会仅因为您的应用程序正在使用CPU而保持您的应用程序处于活动状态。它必须有一种方式来知道您的应用程序仍然有工作要做;这就是为什么Services向操作系统注册,而AsyncTasks则没有。 多线程

AsyncTasks 是关于创建一个后台线程来执行任务,并以线程安全的方式将结果呈现给UI线程。

每次新的AsyncTask执行通常会导致更多的并发(更多的线程),但受到AsyncTasks线程池的限制 [ref]。

另一方面,Service方法总是在UI线程上调用[ref]。这适用于onCreate()onStartCommand()onDestroy()onServiceConnected()等。因此,在某种意义上,Services不会在后台“运行”。一旦它们启动(onCreate()),它们只是“坐”在那里——直到需要清理、执行onStartCommand()等操作。

换句话说,添加额外的Services不会导致更多并发。由于它们运行在UI线程上,因此Service方法不是处理大量工作的好地方。
当然,您可以扩展Service,添加自己的方法,并从任何线程调用它们。但如果这样做,线程安全的责任就在您身上,而不是框架。
如果您想要在Service中添加后台线程(或其他类型的工作程序),则可以自由地这样做。例如,您可以在Service.onCreate()中启动后台线程/AsyncTask。但并非所有用例都需要这样做。例如:
  • 您可能希望保持 Service 运行,以便可以在“后台”(也就是说,没有任何屏幕上的 Activities)继续获取位置更新。
  • 或者,您可能希望保持应用程序处于活动状态,以便可以长期注册“隐式”BroadcastReceiver(在 API 26 之后,您不能总是通过清单来实现这一点,因此必须在运行时进行注册 [ref])。

这两种用例都不需要大量的 CPU 活动;它们只需要应用程序不被杀死即可。

作为 Workers

Services 不是面向任务的。它们不像 AsyncTasks 那样设置为“执行任务”和“传递结果”。Services 不解决任何线程安全问题(尽管所有方法都在单个线程上执行)。另一方面,AsyncTasks 可以处理这些复杂性。

请注意,AsyncTask已被标记为弃用。但这并不意味着您应该用Services替换AsyncTasks!(如果您从这个答案中学到了任何东西,那么这一点应该很清楚。) 简而言之 Services主要是为了“存在”。它们就像一个屏幕外的Activity,提供了一个理由让应用程序保持活动状态,而其他组件负责执行“工作”。AsyncTasks执行“工作”,但它们本身不会保持进程处于活动状态。

1
在少数情况下,两者都可以实现相同的功能。与Async Task不同,服务具有自己的生命周期并继承上下文(服务比Async Task更健壮)。即使您已退出应用程序,服务也可以运行。如果您想要在应用关闭后执行某些操作并且还需要上下文变量,则会选择服务。
例如:如果您想播放音乐并且不希望在用户离开应用程序时暂停,则肯定会选择服务。

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