Android Service是否在单独的线程而非UI线程中运行?

36

我目前正在使用alarmmanager来启动一个服务,以便将位置信息发送到http。问题是当管理器启动并运行服务时,界面似乎会停止一段时间。我想问一下服务线程是否与UI线程分离?


你可能应该了解一下AsyncTask - s_nair
@ericlee 很抱歉回复晚了:看看这个例子 http://code2concept.blogspot.in/2015/02/androidhow-to-find-on-which-thread-code.html - Nitesh Tiwari
在这种情况下,IntentService可能比Service更有效。 - IgorGanapolsky
3个回答

53

需要澄清的是:应用程序的主线程并不总是UI线程。

例如:如果一个活动被停止,onStop()会被调用,因此UI线程会从该活动中移开,并移到同一应用程序或不同应用程序中的另一个活动中。

然而,这并不意味着该应用程序不再活动。此外,如果后台运行着一个(已启动的)服务,它可能会继续运行一段时间,直到终止或Android操作系统由于资源不足而终止它。

在这段时间里,谁在运行这个服务?谁触发了onStop()或onDestroy()?这是由应用程序的主线程完成的。

UI线程是一种单例模式,每次只能由一个可见活动使用。应用程序的主线程要么加入/附加到UI线程,要么另一个线程获取它。然而,这并不意味着应用程序没有自己的主线程。

这种行为来自于Android系统基于Linux / Unix的基础知识。大多数开发人员不知道的是:应用程序是Linux / Unix操作系统中的“用户”。

每当调用应用程序时,就类似于用户登录到系统中。在应用程序的情况下,用户ID是唯一的应用程序ID,而不需要密码。新登录的“用户”(即Android应用程序)会获得一个进程和资源,例如Java虚拟机的实例。该进程专门用于此用户,资源包括文件系统配额、文件描述符和处理器允许它与操作系统通信。

Android应用程序的主线程是从Android操作系统交给该应用程序的进程创建的根线程。在该应用程序中创建的任何新线程都将始终返回到主线程。

应用程序的主线程可以访问的系统资源之一是UI线程。因此,应用程序可以请求主线程,但请求可能会被拒绝(或授权)。例如:如果应用程序进程超过其允许的内存分配大小,Android操作系统可能会拒绝访问UI线程并甚至销毁应用程序并终止该进程。

通过在AndroidManifest.xml中定义,可以为一个应用程序(Unix进程分支)定义多个进程。但请注意,分配给每个进程的资源将不同,即每个进程都将有自己的VM,因此在不同进程中维护的对象将无法通过相同的JVM堆共享信息。


4
以前从未听说过这个……我一直以为应用程序主线程就是用户界面线程。 - KunYu Tsai
@Gabriel:这种行为源于Android系统的Linux\Unix基础。大多数开发人员不知道的是:应用程序是Linux\Unix操作系统中的一个“用户”。这意味着每个应用程序在Android中都是一个用户?你能否提供更多相关信息吗? - Yogesh Seralia
@IgorGanapolsky 当你说“应用程序的主线程已连接/附加到UI线程”时,你是什么意思? - Khalil
我同意@Gabriel在开发者页面上看到的线程部分所说的内容。如果一个应用程序组件启动并且已经存在该应用程序的进程(因为另一个无法是UI组件的组件存在),则该组件将在该进程内启动并使用相同的执行线程。 - Ali Ahsan
显示剩余2条评论

52

从Android文档中复制:

注意:服务在其托管进程的主线程中运行——服务不创建自己的线程,也不在单独的进程中运行(除非您另外指定)。这意味着,如果您的服务将执行任何CPU密集型工作或阻塞操作(例如MP3播放或网络),您应该在服务内部创建一个新线程来执行该工作。通过使用单独的线程,您将减少应用程序未响应(ANR)错误的风险,并且应用程序的主线程可以保持专用于与活动的用户交互。

服务概述

如果您不想自己管理线程,请使用IntentService。或者使用AsyncTasks


3

来自安卓开发者:

什么是Service?

关于Service类,大多数人的困惑实际上都是围绕着它不是什么而产生的:

Service不是一个独立的进程。Service对象本身并不意味着它在自己的进程中运行;除非另有说明,否则它将在与其所属的应用程序相同的进程中运行。 Service不是一个线程。它本身不是在主线程之外执行工作的方式(以避免应用程序无响应错误)。 因此,Service本身实际上非常简单,提供了两个主要功能:

一种机制,让应用程序告诉系统它想要在后台做什么(即使用户没有直接与应用程序交互)。这对应于对Context.startService()的调用,它要求系统为服务安排工作,直到服务或其他人明确地停止它。 一种机制,让应用程序向其他应用程序公开一些功能。这对应于对Context.bindService()的调用,它允许建立长期连接以与服务进行交互。 当Service组件实际上被创建时,出于这两个原因之一,系统实际上所做的就是实例化组件并在主线程上调用其onCreate()和任何其他适当的回调。由Service来实现这些行为,例如在其中创建一个次要线程来执行其工作。

请注意,由于Service本身非常简单,因此您可以将与其交互的方式简单或复杂地处理:从将其视为本地Java对象,您可以直接调用其方法(如Local Service示例所示),到使用AIDL提供完整的可远程接口。


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