在Android平台中,Service和IntentService有什么区别?

823

我正在寻找一个例子,说明使用IntentService可以做到的事情,而使用Service则无法做到(反之亦然)?

我还了解到,IntentService在不同的线程中运行,而Service则不会。因此,据我所知,在其自己的线程中启动服务就像启动IntentService一样。这是正确的吗?


50
IntentService 用于短期任务(等等),而 Service 用于长期任务。你在哪里读到的? - njzk2
9
另外,我建议你阅读 IntentService 的源代码。它能清楚地展示它的作用和功能。 - njzk2
1
我在看到你的评论后编辑了我的问题。 - roiberg
9
IntentService的代码:https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/app/IntentService.java - greg7gkb
2
之前评论中的链接(由greg7gkb提供)是一篇很棒的阅读材料。 - DSlomer64
11个回答

1428

Tejas Lagvankar写了一篇很好的关于这个主题的文章

何时使用?

  • Service可用于没有UI的任务,但不应太长。如果需要执行长时间的任务,必须在Service中使用线程。

  • IntentService通常用于长时间的任务且不与主线程通信。如果需要通信,则可以使用Main Thread handler或broadcast intents。另一个使用情况是需要回调(Intent触发的任务)。

如何触发?

  • 通过调用方法startService()来触发服务。

  • IntentService使用Intent触发,它会生成一个新的工作线程,并在该线程上调用方法onHandleIntent()。

触发自

  • 服务和IntentService可以从任何线程,活动或其他应用程序组件触发。

运行在

  • 服务在后台运行,但在应用程序的主线程上运行。

  • IntentService在单独的工作线程上运行。

限制/缺点

  • 服务可能会阻塞应用程序的主线程。

  • IntentService无法并行运行任务。因此,所有连续的意图将进入工作线程的消息队列中,并按顺序执行。

何时停止?

  • 如果您实现了一个服务,当其工作完成时,调用stopSelf()stopService()停止服务是您的责任。(如果您只想提供绑定,则不需要实现此方法)。

  • IntentService会在处理完所有启动请求后停止服务,因此您永远不需要调用stopSelf()


13
简短而精炼,但最好编辑您的答案包括CommonsWare的观点,因为很多人只阅读被接受或得到最多赞的答案。 - Shirish Herwade
12
一个服务是一个应用程序组件,可以在后台执行长时间运行的操作,并且不提供用户界面。服务在其托管进程的主线程中运行。服务不会创建自己的线程,也不会在单独的进程中运行(除非您另有指定)。这意味着,如果您的服务将执行任何CPU密集型工作或阻塞操作(例如MP3播放或网络操作),则应在服务内部创建一个新线程来完成该工作。 - José Juan Sánchez
8
"IntentService必须从主线程触发。" 你确定吗? 在我的MainActivity onCreate()中,当我从一个新线程调用IntentService(如下所示的代码)时,它仍然可以工作。new Thread(new Runnable() { @Override public void run() { Intent intent = new Intent(context, HelloIntentService.class); startService(intent); } }).start(); - Ashok Bijoy Debnath
9
您说得对!ServicesIntentServices可以从任何线程、活动或其他应用程序组件启动。我刚刚编辑了答案的文本以解决这个问题。感谢您的编辑建议! :) - José Juan Sánchez
2
服务在后台运行,但它运行在应用程序的主线程上。这是错误的。Service 是一个对象,它不在任何线程上运行。Service 的方法可以在任何线程上运行,而生命周期方法(onCreate()onStartCommand()onDestroy())由 Android 框架在主(UI)线程上调用。实现 Service 时,通常会启动自己的工作线程或后台线程,并在这些线程上执行长时间运行的操作。IntentService 只是 Service 的扩展,为您完成其中一些操作。 - David Wasser
显示剩余12条评论

174

如果有人可以给我展示一个只能使用IntentService而不能用Service完成的示例,或者反过来。

根据定义,这是不可能的。 IntentService是用Java编写的Service子类。因此,IntentService做的任何事情,Service都可以通过包含IntentService使用的相关代码来完成。

使用自己的线程启动服务就像启动IntentService。 是吗?

IntentService的三个主要特点是:

  • 后台线程

  • 将传递到onStartCommand()Intent自动排队处理,因此如果一个Intent正在由后台线程的onHandleIntent()处理,其他命令会排队等待轮流执行

  • 当队列为空时,通过调用stopSelf()自动关闭IntentService

所有这些都可以在不扩展IntentService的情况下通过Service实现。


7
有点晚了,但我发现使用startService调用的Service只能运行约10秒钟就会抛出ANR错误。然而,通过广播一个Intent启动的IntentService似乎没有这个限制。 - edthethird
16
这是因为您正在阻塞主应用程序线程。所有组件的生命周期方法,包括“Service”的“onStartCommand()”,都在主应用程序线程上调用。如果您在没有冻结UI的情况下占用此线程超过几毫秒,则会出现类似ANR的服务故障,而如果占用了几秒钟,则会发生更严重的问题。请确保在后台处理任何耗时操作,以避免这种情况的发生。 - CommonsWare
4
是的,我评论得太早了。我应该在onHandleIntent而不是onStartCommand中进行工作--看起来onStartCommand在UI线程上运行,然而,在执行onHandleIntent时会产生一个单独的线程。 - edthethird
3
@IgorGanapolsky:如果没有更多的工作要完成,IntentService会在onHandleIntent()返回后自己调用。 - CommonsWare
1
问题不在于英语,而在于编程。例如,“我已经关闭了应用程序”没有明确的定义,因此我无法告诉您发生了什么。我也不知道“我已经关闭了应用程序”与“1小时后将下载”有什么关系。您可以考虑提出一个单独的Stack Overflow问题,在那里您可以提供“1小时后将下载”的[mcve]。在那里,您可以详细解释“我已经关闭了应用程序”的含义(例如,用户具体执行哪些操作来关闭应用程序?)。 - CommonsWare
显示剩余12条评论

44

服务

  • 通过startService()调用。
  • 可以由任何线程触发。
  • 主线程上运行。
  • 可能会阻塞主(UI)线程。总是使用服务内的线程进行长时间任务。
  • 一旦任务完成,我们有责任调用stopSelf()stopService()来停止服务。

IntentService

  • 通常执行长时间任务,不与主线程通信,如果需要通信,则通过HandlerBroadcastReceiver完成。
  • 通过Intent调用。
  • 主线程触发。
  • 在单独的线程上运行。
  • 不能并行运行任务,并且在同一个工作线程上排队多个意图。

1
一个 IntentService 也可以通过 startService 调用。请相应地编辑您的答案并使其连贯。 - daparic

42

不要重复造轮子

IntentService 扩展了 Service 类,这意味着 IntentService 是有意为之的同样的目的。

那么目的是什么呢?

`IntentService` 的目的是使我们更轻松地运行后台任务,甚至不必担心以下问题:

  • 创建工作线程

  • 按顺序排队处理多个请求(Threading)

  • 销毁Service

所以不需要Service 可以执行IntentService执行的任何任务。如果您的要求符合上述标准,则不必在 Service 类中编写这些逻辑。

主要区别

Service 运行在 UI 线程上,而 IntentService 运行在单独的线程上

何时使用 IntentService?

当您想要依次执行多个存在于 Activity 范围之外的后台任务时,IntentService 是完美的选择。

IntentService 是如何由 Service 创建而来的

普通服务运行在 UI 线程上(任何 Android 组件类型都默认在 UI 线程上运行,例如 ActivityBroadcastReceiverContentProviderService)。如果您需要执行一些可能需要一段时间才能完成的工作,则必须创建一个线程。在多个请求的情况下,您将不得不处理同步

IntentService已经给你提供了一些默认的实现,可以为你完成这些任务。根据开发者页面的说明:
  1. IntentService创建一个工作线程

  2. IntentService创建了一个工作队列,按顺序将请求发送到onHandleIntent()方法中

  3. 当没有任务时,IntentService调用stopSelf()方法

  4. onBind()方法提供了默认实现,该实现为空

  5. onStartCommand()的默认实现会将Intent请求发送到工作队列,并最终到达onHandleIntent()


当您想要依次执行多个超出Activity范围的后台任务时,IntentService是完美的选择。您需要示例吗? - Wini
2
从播放列表中逐一下载歌曲。@Wini - Rohit Singh

15

为已接受的答案添加积分:

查看Android API中IntentService的用法。 例如:

public class SimpleWakefulService extends IntentService {
    public SimpleWakefulService() {
        super("SimpleWakefulService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {  ...}

要为您的应用程序创建IntentService组件,请定义一个扩展IntentService的类,并在其中定义一个覆盖onHandleIntent()的方法。
此外,查看IntentService的源代码,包括其构造函数和生命周期方法,如onStartCommand...
  @Override
    public int More ...onStartCommand(Intent intent, int flags, int startId) {
       onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

将一个AsyncTask与Service一起使用是许多用例中最好的方法之一,其中有效载荷不是很大。或者只需创建一个扩展IntentSerivce的类。从Android 4.0版本开始,所有网络操作都应该在后台进程中进行,否则应用程序编译/构建失败。从UI中分离出单独的线程。AsyncTask类提供了一种从UI线程启动新任务的最简单方式之一。有关此主题的更多讨论,请参见博客文章。
来自Android开发人员指南
IntentService是处理按需异步请求(表示为Intents)的服务的基类。客户端通过startService(Intent)调用发送请求;需要时启动服务,使用工作线程依次处理每个Intent,并在没有工作时停止自身。
在IntentService中使用的设计模式:
这种“工作队列处理器”模式通常用于从应用程序的主线程卸载任务。 IntentService类存在是为了简化此模式并处理机制。要使用它,请扩展IntentService并实现onHandleIntent(Intent)。 IntentService将接收Intents,启动工作线程并在适当时停止服务。
所有请求都在一个工作线程上处理--他们可以花费任意长的时间(并且不会阻塞应用程序的主循环),但是一次只处理一个请求。
IntentService类提供了一个简单的结构,用于在单个后台线程上运行操作。这使它能够处理长时间运行的操作,而不影响用户界面的响应性。此外,IntentService不受大多数用户界面生命周期事件的影响,因此它可以在会关闭AsyncTask的情况下继续运行。
IntentService有一些限制:
它无法直接与您的用户界面交互。要将其结果放入UI中,必须将它们发送到Activity中。 工作请求按顺序运行。如果在IntentService中正在运行操作,并且您发送了另一个请求,则该请求将等待第一个操作完成。 在IntentService上运行的操作不能被中断。 然而,在大多数情况下,
IntentService是简单后台操作的首选方式。

**

Volley库

有一个名为Volley库的库,用于开发Android网络应用程序。 该源代码可在GitHub上公开获取。

Android官方文档中的后台作业最佳实践: 有助于更好地理解意图服务、线程、处理器、服务,并且执行网络操作


1
如果您能给出简短、直接的答案,那就更好了。 - eRaisedToX

14

我相信你可以通过简单地搜索“Android IntentService vs Service”之类的东西,找到一个广泛的差异列表。

举个例子,其中一个更重要的区别是,IntentService在完成任务后会自行关闭。

一些快速编造的例子:

IntentService:如果您想在打开应用程序时下载大量图像。这是一次性过程,可以在所有内容下载完成后进行清理。

Service:一个服务,将不断用于通过Web API调用在您的应用程序和后端之间进行通信。即使它已经完成了当前的任务,您仍然希望它在几分钟后继续存在,以进行更多的通信。


2
我没有找到一个只能用其中一种方式完成而不能用另一种方式完成的例子,只是一些对我没有帮助的解释。 - roiberg
1
试试这个网站,它有很多关于基本Android概念的良好解释和不错的示例 http://www.vogella.com/articles/AndroidServices/article.html - Stefan de Bruijn
4
这是“如何使用”的另一个例子,涉及使用服务和意图服务的具体情况。请给我一个理论实例,而非“如何使用”或其他链接。 我并不是让你为我“工作”,只是因为我已经看了所有的链接,却仍然不确定。 - roiberg
5
这是一个非常重要的区别。例如,如果您使用服务与服务器保持持久连接,您不能使用 IntentService,因为它在完成所有任务后立即终止。 - pelotasplus
29
我谷歌搜索后跳转到了这里,现在我被卡在了一个无限循环中。 - Lou Morda
显示剩余3条评论

12

IntentService

IntentService 运行在自己的线程上。当它完成时,会自动停止。更像是一次性启动而不需要等待任务完成。 后续调用将被排队。适合排队调用。如果需要的话,您还可以在 IntentService 中旋转多个线程- 可以使用 ThreadPoolExecutor 来实现这一点。 我之所以这样说,是因为很多人问我“为什么使用 IntentService 因为它不支持并行执行”。 IntentService 只是一个线程。您可以在其中执行任何需要的操作- 甚至可以旋转多个线程。唯一的注意事项是,IntentService 会在您旋转这些多个线程时立即结束。它不等待这些线程返回。因此,在这种情况下,建议使用 ThreadPoolExecutor

  • 适合同步、上传等操作。

Service

默认情况下,Service 在主线程上运行。您需要旋转工作线程来完成您的任务。 您需要显式停止 service。 我在需要在后台运行任务时,例如 Headless service 的情况下使用了它。

  • 同样,如果需要,您可以运行多个线程。
  • 可用于音乐播放器等应用程序。

如果需要的话,您始终可以使用 BroadcastReceivers 与您的活动进行通信。


9
IntentService是Service的扩展,旨在简化需要在后台和独立线程中执行任务的执行。IntentService启动时创建一个线程并在该线程中运行其任务。一旦完成,它将清理所有内容。同时只能运行一个IntentService实例,多个调用将被排队。它非常简单易用,对于许多用途非常方便,例如下载东西。但它有限制,可能会使您想要使用更基本(不简单)的Service。例如,连接到xmpp服务器并由活动绑定的服务无法简单地使用IntentService完成。您最终将忽略或覆盖IntentService的内容。

似乎大多数想要在后台运行真正长时间服务的人最终都会尝试了解 IntentService,因为文档让人觉得它就是用来做这件事的,但你完全可以使用 new Thread(new Runnable()).start() 来完成同样的工作。换句话说,当文档提到“生成一个新线程”时,它所做的就是这些,它不会将其移动到一个单独的 进程 中,而这实际上是大多数人在想要将一些正在运行的代码从活动中分离出来时所寻求的!(因为仅产生_线程_只需要一行代码)。 - Lassi Kinnunen
IntentService 还负责线程的生命周期,并使用 Looper 帮助调度程序。它还确保只有一个实例正在运行,并排队其他调用。 - njzk2

7

Android IntentService vs Service

1. Service(服务)

  • 使用startService()来调用服务。
  • 服务可以从任何线程中调用。
  • 默认情况下,服务在应用程序的主线程上运行后台操作。因此,它可能会阻止应用程序的用户界面。
  • 多次调用服务将创建多个实例。
  • 服务需要使用stopSelf()或stopService()进行停止。
  • Android服务可以并行运行操作。

2. IntentService(意图服务)

  • 使用Intent来调用IntentService。
  • 只能从主线程中调用IntentService。
  • IntentService创建一个单独的工作线程来运行后台操作。
  • 多次调用IntentService不会创建多个实例。
  • 当队列完成后,IntentService会自动停止。无需触发stopService()或stopSelf()。
  • 在IntentService中,多个意图调用会自动排队,它们将按顺序执行。
  • IntentService不能像服务一样并行运行操作。

参考来源:这里


6
如果有人能向我展示一个使用IntentService可以做到而service做不到的事情的示例,以及反过来。 IntentService不能用于长时间监听,例如XMPP监听器,它只是一个一次性运算符,完成工作后就会结束。
此外,它只有一个线程工作器,但通过技巧,您可以将其用作无限制的工作器。

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