如何检查Android上的服务是否正在运行?
如何检查后台服务是否正在运行?
我想要一个可以切换服务状态的 Android 活动 - 如果服务关闭,它可以让我打开它;如果服务打开,我可以关闭它。
How do I check if a background service is running?
I want an Android activity that toggles the state of the service -- it lets me turn it on if it is off and off if it is on.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
我在活动内部使用以下内容:
我称之为使用:
这工作可靠,因为它基于 Android 操作系统通过
ActivityManager#getRunningServices
。所有使用 onDestroy 或 onSomething 事件或 Binder 或静态变量的方法都无法可靠地工作,因为作为开发人员,您永远不知道 Android 何时决定终止您的进程或哪个进程是否调用上述回调。 请注意生命周期事件表中的“killable”列Android 文档。
I use the following from inside an activity:
And I call it using:
This works reliably, because it is based on the information about running services provided by the Android operating system through
ActivityManager#getRunningServices
.All the approaches using
onDestroy
oronSomething
events or Binders or static variables will not work reliably because as a developer you never know, when Android decides to kill your process or which of the mentioned callbacks are called or not. Please note the "killable" column in the lifecycle events table in the Android documentation.不久前我也遇到了同样的问题。 由于我的服务是本地的,因此我最终只是使用服务类中的静态字段来切换状态,如 hackbod 此处
编辑(记录):
这是 hackbod 提出的解决方案:
I had the same problem not long ago. Since my service was local, I ended up simply using a static field in the service class to toggle state, as described by hackbod here
EDIT (for the record):
Here is the solution proposed by hackbod:
知道了!
您必须调用
startService()
才能正确注册您的服务,并且传递BIND_AUTO_CREATE
是不够的。现在是 ServiceTools 类:
Got it!
You MUST call
startService()
for your service to be properly registered and passingBIND_AUTO_CREATE
will not suffice.And now the ServiceTools class:
一个小小的补充是:
我的目标是了解服务是否正在运行,而无需在服务未运行时实际运行它。
调用bindService或调用可以被服务捕获的意图并不是一个好主意,因为如果服务未运行,它将启动服务。
所以,正如miracle2k建议的,最好是在服务类中有一个静态字段来知道服务是否已经启动。
为了使其更加清晰,我建议使用非常非常懒惰的获取方式将服务转换为单例:也就是说,根本没有实例化 通过静态方法实现单例实例。 服务/单例的静态 getInstance 方法仅返回单例的实例(如果已创建)。 但它实际上并没有启动或实例化单例本身。 该服务只能通过正常的服务启动方法启动。
然后,修改单例设计模式以将令人困惑的 getInstance 方法重命名为类似于 isInstanceCreated() : boolean 方法的内容会更加清晰。
代码如下所示:
这个解决方案很优雅,但只有当您有权访问服务类并且仅适用于服务的应用程序/包内的类时,它才相关。 如果您的类位于服务应用程序/包之外,那么您可以查询 ActivityManager,其限制由 Pieter-Jan Van Robays 强调。
A small complement is:
My goal is to know wether a service is running without actualy running it if it is not running.
Calling bindService or calling an intent that can be caught by the service is not a good idea then as it will start the service if it is not running.
So, as miracle2k suggested, the best is to have a static field in the service class to know whether the service has been started or not.
To make it even cleaner, I suggest to transform the service in a singleton with a very very lazy fetching: that is, there is no instantiation at all of the singleton instance through static methods. The static getInstance method of your service/singleton just returns the instance of the singleton if it has been created. But it doesn't actualy start or instanciate the singleton itself. The service is only started through normal service start methods.
It would then be even cleaner to modify the singleton design pattern to rename the confusing getInstance method into something like the
isInstanceCreated() : boolean
method.The code will look like:
This solution is elegant, but it is only relevant if you have access to the service class and only for classes iside the app/package of the service. If your classes are outside of the service app/package then you could query the ActivityManager with limitations underlined by Pieter-Jan Van Robays.
您可以使用这个(我还没有尝试过,但我希望它有效):
如果已经有一个正在运行的服务,startService 方法将返回一个 ComponentName 对象。 如果不是,则返回 null。
请参阅公共抽象 ComponentName startService (意向服务)。
我认为这不像检查,因为它正在启动服务,因此您可以在代码下添加
stopService(someIntent);
。You can use this (I didn't try this yet, but I hope this works):
The startService method returns a ComponentName object if there is an already running service. If not, null will be returned.
See public abstract ComponentName startService (Intent service).
This is not like checking I think, because it's starting the service, so you can add
stopService(someIntent);
under the code.Android 文档摘录:
将此黑客视为“ping”
服务
。 由于我们可以同步广播,因此我们可以在 UI 线程上同步广播并获取结果。Service
Activity
在许多应用程序中,获胜者当然是服务上的静态布尔字段,该字段在
Service.onCreate 中设置为
和true
()Service.onDestroy()
中的false
因为它简单得多。An extract from Android docs:
Think of this hack as "pinging" the
Service
. Since we can broadcast synchronously, we can broadcast and get a result synchronously, on the UI thread.Service
Activity
The winner in many applications is of course a static boolean field on the service that is set to
true
inService.onCreate()
and tofalse
inService.onDestroy()
because it's a lot simpler.另一种使用 kotlin 的方法。 受到其他用户答案的启发
作为 kotlin 扩展
用法
Another approach using kotlin. Inspired in other users answers
As kotlin extension
Usage
检查服务是否正在运行的正确方法是简单地询问它。 在您的服务中实现一个 BroadcastReceiver 来响应来自您的活动的 ping。 当服务启动时注册BroadcastReceiver,当服务销毁时取消注册。 从您的 Activity(或任何组件)发送 本地广播< /a> 意图服务,如果它响应,您就知道它正在运行。 请注意下面代码中 ACTION_PING 和 ACTION_PONG 之间的细微差别。
The proper way to check if a service is running is to simply ask it. Implement a BroadcastReceiver in your service that responds to pings from your activities. Register the BroadcastReceiver when the service starts, and unregister it when the service is destroyed. From your activity (or any component), send a local broadcast intent to the service and if it responds, you know it's running. Note the subtle difference between ACTION_PING and ACTION_PONG in the code below.
我稍微修改了上面提出的解决方案之一,但传递了类而不是通用字符串名称,以便确保比较来自同一方法
class.getName()
的字符串,然后
I have slightly modified one of the solutions presented above, but passing the class instead of a generic string name, in order to be sure to compare strings coming out from the same method
class.getName()
and then
我只想在@Snicolas 的答案中添加一条注释。 以下步骤可用于在调用/不调用
onDestroy()
的情况下检查停止服务。onDestroy()
调用:转到“设置”->“ 应用-> 运行服务 -> 选择并停止您的服务。onDestroy()
未调用:转到“设置”->“ 应用-> 管理应用程序 -> 选择并“强制停止”正在运行服务的应用程序。 但是,由于您的应用程序在这里停止,因此服务实例肯定也会停止。最后,我想提一下,其中提到的在单例类中使用静态变量的方法对我有用。
I just want to add a note to the answer by @Snicolas. The following steps can be used to check stop service with/without calling
onDestroy()
.onDestroy()
called: Go to Settings -> Application -> Running Services -> Select and stop your service.onDestroy()
not Called: Go to Settings -> Application -> Manage Applications -> Select and "Force Stop" your application in which your service is running. However, as your application is stopped here, so definitely the service instances will also be stopped.Finally, I would like to mention that the approach mentioned there using a static variable in singleton class is working for me.
同样,如果人们使用挂起的意图,他们可能会发现另一种更干净的选择(例如使用
AlarmManager
:其中
CODE
是您在类中私有定义的常量,用于标识与您的服务相关的待处理意图。Again, another alternative that people might find cleaner if they use pending intents (for instance with the
AlarmManager
:Where
CODE
is a constant that you define privately in your class to identify the pending intents associated to your service.首先,您不应该使用
ActivityManager
。 (此处讨论)服务可以自行运行,绑定到一个 Activity 或两者。 检查 Activity 是否正在运行的方法是创建一个接口(扩展 Binder),在其中声明
Activity
和Service
的方法, 理解。 您可以通过创建自己的接口来实现此目的,例如在其中声明“isServiceRunning()
”。然后,您可以将您的 Activity 绑定到您的 Service,运行 isServiceRunning() 方法,Service 将检查自身是否正在运行,并向您的 Activity 返回一个布尔值。
您还可以使用此方法来停止您的服务或以其他方式与其交互。
First of all you shouldn't reach the service by using the
ActivityManager
. (Discussed here)Services can run on their own, be bound to an Activity or both. The way to check in an Activity if your Service is running or not is by making an interface (that extends Binder) where you declare methods that both, the
Activity
and theService
, understand. You can do this by making your own Interface where you declare for example "isServiceRunning()
".You can then bind your Activity to your Service, run the method isServiceRunning(), the Service will check for itself if it is running or not and returns a boolean to your Activity.
You can also use this method to stop your Service or interact with it in another way.
onDestroy
并不总是在服务中调用,因此这是没有用的!例如:只需从 Eclipse 进行一项更改即可再次运行该应用程序。 使用 SIG: 9 强制退出应用程序。
onDestroy
isn't always called in the service so this is useless!For example: Just run the app again with one change from Eclipse. The application is forcefully exited using SIG: 9.
下面是一个涵盖所有
If
的优雅技巧。 这仅适用于本地服务。然后后来:
Below is an elegant hack that covers all the
Ifs
. This is for local services only.And then later on:
Xamarin C# 版本:
Xamarin C# version:
对于此处给出的用例,我们可以简单地使用 stopService() 方法的返回值。 如果指定的服务存在并且被杀死,则返回
true
。 否则返回false
。 因此,如果结果为false
,则可以重新启动服务,否则可以确定当前服务已停止。 :) 如果你看看 这个。For the use-case given here we may simply make use of the
stopService()
method's return value. It returnstrue
if there exists the specified service and it is killed. Else it returnsfalse
. So you may restart the service if the result isfalse
else it is assured that the current service has been stopped. :) It would be better if you have a look at this.来电
The call
在您的服务子类中,使用静态布尔值来获取服务的状态,如下所示。
MyService.kt
MainActivity.kt
In your Service Sub-Class Use a Static Boolean to get the state of the Service as demonstrated below.
MyService.kt
MainActivity.kt
在 kotlin 中,您可以在伴随对象中添加布尔变量,并从您想要的任何类中检查其值:
创建和销毁服务时更改它的值
In kotlin you can add boolean variable in companion object and check its value from any class you want:
Change it value when service is created and destroyed
对于 kotlin,您可以使用以下代码。
For kotlin, you can use the below code.
在 TheServiceClass 内部定义:
然后在 onStartCommand(...) 中
,然后从任何类调用
if(TheServiceClass.serviceRunning == true)
。Inside TheServiceClass define:
Then In onStartCommand(...)
Then, call
if(TheServiceClass.serviceRunning == true)
from any class.简单地使用绑定而不创建自动- 请参阅 ps。 并更新...示例:
为什么不使用? getRunningServices()
注意:此方法仅用于调试或实现服务管理类型用户界面。
ps。 android 文档具有误导性,我在 google tracker 上提出了一个问题,以消除任何疑虑:
https:/ /issuetracker.google.com/issues/68908332
我们可以看到绑定服务实际上通过 Service 缓存绑定器通过 ActivityManager 绑定器调用事务 - 我不跟踪哪个服务负责绑定,但我们可以看到绑定的结果is:
事务是通过binder进行的:
next:
这是在ActivityThread中设置的 via:
这是在ActivityManagerService中调用的方法:
then:
但是没有“活动”,只有窗口包和警报..
所以我们需要返回调用:
this通过:进行调用
:这会导致:
这是本机方法....
我现在没有时间深入研究c,所以在我剖析休息调用之前我会暂停我的回答。
但检查服务是否正在运行的最佳方法是创建绑定(如果未创建绑定,则服务不存在) - 并通过绑定查询服务的状态(使用其状态上存储的内部标志) 。
更新 23.06.2018
我发现这些很有趣:
简而言之:)
“为已绑定的服务提供绑定器。此方法是同步的,如果目标服务不存在,则不会启动它。”
public IBinder peekService(意图服务,字符串解析类型,
String CallingPackage) 抛出 RemoteException;
simple use bind with don't create auto- see ps. and update...example :
why not using? getRunningServices()
Note: this method is only intended for debugging or implementing service management type user interfaces.
ps. android documentation is misleading i have opened an issue on google tracker to eliminate any doubts:
https://issuetracker.google.com/issues/68908332
as we can see bind service actually invokes a transaction via ActivityManager binder through Service cache binders - i dint track which service is responsible for binding but as we can see the result for bind is:
transaction is made through binder:
next:
this is set in ActivityThread via:
this is called in ActivityManagerService in method:
then:
but there is no "activity" only window package and alarm..
so we need get back to call:
this makes call through:
which leads to :
and this is native method....
i don't have time now to dug in c so until i dissect rest call i suspend my answer.
but best way for check if service is running is to create bind (if bind is not created service not exist) - and query the service about its state through the bind (using stored internal flag on it state).
update 23.06.2018
i found those interesting:
in short :)
"Provide a binder to an already-bound service. This method is synchronous and will not start the target service if it is not present."
public IBinder peekService(Intent service, String resolvedType,
String callingPackage) throws RemoteException;
请使用此代码。
Please use this code.
这是我提出的很好的解决方案,但它仅适用于在单独进程中运行的服务。 这可以通过在清单中添加
android:process
属性来实现,例如现在您的服务将在具有给定名称的单独进程中运行。 在您的应用中,您可以调用
Which 将在服务正在运行时返回
true
,否则返回false
。重要:请注意,它会显示您的服务何时启动,但是当您禁用它时(即系统与其解除绑定后),该进程仍然可以活动。 因此,您可以简单地强制将其删除:
然后它就可以正常工作了。
Here's good solution I've come up with, but it works only for the Services running in separate processes. This can be achieved by adding an
android:process
attribute in the manifest, e.g.Now your service will be running in a separate process with the given name. From your app you can call
Which will return
true
if the service is running andfalse
otherwise.IMPORTANT: note that it will show you when your service was started, but when you disable it (meaning, after system unbinds from it) the process can still be alive. So you can simply force it's removal:
Then it works perfectly.
可以有多个具有相同类名的服务。
我刚刚创建了两个应用程序。 第一个应用程序的包名称是
com.example.mock
。 我在应用程序中创建了一个名为lorem
的子包和一个名为Mock2Service
的服务。 所以它的完全限定名称是com.example.mock.lorem.Mock2Service
。然后我创建了第二个应用程序和一个名为
Mock2Service
的服务。 第二个应用程序的包名称是com.example.mock.lorem
。 该服务的完全限定名称也是com.example.mock.lorem.Mock2Service
。这是我的 logcat 输出。
更好的想法是比较
ComponentName
实例,因为ComponentName
的equals()
会比较包名称和类名称。 并且设备上不能安装两个具有相同包名的应用程序。ComponentName
的 equals() 方法。组件名称
There can be several services with the same class name.
I've just created two apps. The package name of the first app is
com.example.mock
. I created a subpackage calledlorem
in the app and a service calledMock2Service
. So its fully qualified name iscom.example.mock.lorem.Mock2Service
.Then I created the second app and a service called
Mock2Service
. The package name of the second app iscom.example.mock.lorem
. The fully qualified name of the service iscom.example.mock.lorem.Mock2Service
, too.Here is my logcat output.
A better idea is to compare
ComponentName
instances becauseequals()
ofComponentName
compares both package names and class names. And there can't be two apps with the same package name installed on a device.The equals() method of
ComponentName
.ComponentName
如果您有一个多模块应用程序,并且您想知道某个模块中的服务是否正在运行,而该模块不依赖于包含该服务的模块,则可以使用此函数:
Usage for
MyService
服务:If you have a multi-module application and you want to know that service is running or not from a module that is not depends on the module that contains the service, you can use this function:
Usage for
MyService
service:这更适用于意图服务调试,因为它们生成线程,但也可能适用于常规服务。 感谢 Binging,我找到了这个线程。
在我的例子中,我使用调试器并找到了线程视图。 它看起来有点像 MS Word 中的项目符号图标。 无论如何,您不必处于调试器模式即可使用它。 单击该进程,然后单击该按钮。 任何意图服务都会在运行时显示,至少在模拟器上。
This applies more towards Intent Service debugging since they spawn a thread, but may work for regular services as well. I found this thread thanks to Binging
In my case, I played around with the debugger and found the thread view. It kind of looks like the bullet point icon in MS Word. Anyways, you don't have to be in debugger mode to use it. Click on the process and click on that button. Any Intent Services will show up while they are running, at least on the emulator.
如果服务属于另一个进程或APK,请使用基于ActivityManager的解决方案。
如果您有权访问其源代码,则只需使用基于静态字段的解决方案即可。 但我建议使用 Date 对象来代替布尔值。 当服务运行时,只需将其值更新为“now”,完成后将其设置为 null。 从活动中,您可以检查其是否为空或日期是否太旧,这意味着它没有运行。
您还可以从您的服务发送广播通知,指示该服务正在运行进一步的信息(例如进度)。
If the service belongs to another process or APK use the solution based on the ActivityManager.
If you have access to its source, just use the solution based on a static field. But instead using a boolean I would suggest using a Date object. While the service is running, just update its value to 'now' and when it finishes set it to null. From the activity you can check if its null or the date is too old which will mean that it is not running.
You can also send broadcast notification from your service indicating that is running along further info like progress.
我对基于
ActivityManager::getRunningServices
的答案进行了 kotlin 转换。 将此功能放入活动中-My kotlin conversion of the
ActivityManager::getRunningServices
based answers. Put this function in an activity-