如何检查服务是否在Android上运行?


936

如何检查后台服务是否正在运行?

我想要一个可切换服务状态的Android活动-它可以让我在关闭状态下将其打开,在开启状态下将其关闭。



17
正确的答案在下面,而不是一个正确的答案:stackoverflow.com/a/5921190/2369122
toidiu 2015年

1
@toidiu如果尚未像nerfed那样getRunningTasks(),那可能会。
凯文·克鲁姆维德

使用getSystemService()函数可以检索所有正在运行的服务。遍历它并检查您的服务是否存在于列表中,这里您可以看到一个小样本wiki.workassis.com/android-check-the-service-is-running
Bikesh M,

Answers:


292

我不久前有同样的问题。因为我的服务是本地的,最后我简单地使用在服务类切换状态静态字段,如hackbod描述这里

编辑(记录):

这是hackbod提出的解决方案:

如果您的客户端和服务器代码是同一.apk的一部分,并且您使用具体的Intent(用于指定确切的服务类)绑定到服务,则只需在服务运行时将其设置为全局变量即可您的客户可以检查。

我们故意没有API来检查服务是否正在运行,因为当您想要执行类似的操作时,几乎会失败,您最终会在代码中出现竞争条件。


27
@Pacerier,您引用的解决方案要求启动服务,我认为最好的灵活解决方案应允许您检查服务是否正在运行而不启动它。
汤姆

17
如果服务被系统停止,该怎么办?如何检测并切换变量?
jmng 2014年

23
当该应用程序被杀死时,它已启动的服务也将被杀死,但onDestroy()不会调用该服务。因此,在这种情况下无法更新静态变量,从而导致行为不一致。
faizal

5
@faizal是否还会重新初始化静态变量,从而将其重新设置为指示该服务不再运行的默认值?
PabloC 2014年

12
@faizal,本地服务不是一个单独的进程,因此如果服务被杀死,则应用程序也会被杀死。
2014年

1674

我在活动中使用以下内容:

private boolean isMyServiceRunning(Class<?> serviceClass) {
    ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (serviceClass.getName().equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}

我称它为:

isMyServiceRunning(MyService.class)

这是可靠的,因为它基于有关Android操作系统通过ActivityManager#getRunningServices提供的运行服务的信息。

所有使用onDestroy或onSometing事件或Binders或静态变量的方法都无法可靠地工作,因为作为开发人员,您永远不知道Android何时决定终止您的进程或是否调用了上述回调。请注意Android文档中生命周期事件表中的“ killable”列。


85
感谢您的解决方案。我想补充:除了“com.example.MyService”更优雅的使用MyService.class.getName()
peter.bartos

10
我个人使用静态字段。尽管使用getRunningServices()是更健壮的解决方案,但我相信在这两个解决方案中都需要在健壮性和效率/简单性之间进行权衡。如果您需要经常检查某个服务是否正在运行,那么遍历潜在的30多个正在运行的服务不是很理想。很少有服务被系统破坏的情况,可以通过try / catch块或使用START_STICKY来处理。
robguinness

80
不,这不是正确的答案,因为它也写在文档中:“注意:此方法仅用于调试或实现服务管理类型的用户界面。” 这不是为了控制流程!
2012年

40
人们发现必须经过所有检查服务器是否正在运行的情况很优雅?
Rui Marques 2012年

79
开始的AndroidØgetRunningServices已被弃用。该答案需要更新才能获得较新的版本。
poring91

75

得到它了!

必须要求startService()您的服务进行正确的注册,并且通过BIND_AUTO_CREATE还不够。

Intent bindIntent = new Intent(this,ServiceTask.class);
startService(bindIntent);
bindService(bindIntent,mConnection,0);

现在是ServiceTools类:

public class ServiceTools {
    private static String LOG_TAG = ServiceTools.class.getName();

    public static boolean isServiceRunning(String serviceClassName){
        final ActivityManager activityManager = (ActivityManager)Application.getContext().getSystemService(Context.ACTIVITY_SERVICE);
        final List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);

        for (RunningServiceInfo runningServiceInfo : services) {
            if (runningServiceInfo.service.getClassName().equals(serviceClassName)){
                return true;
            }
        }
        return false;
     }
}

这只会列出系统服务,不是吗?因此,我的本地服务将从列表中排除,我会得到错误的信息;(
Ewoks

这适用于外部服务,如果您正在运行,则本地服务非常明显。
凯文·帕克

11
抱歉,但我必须说这是超级愚蠢的答案。为什么它是如此明显?
Ewoks

10
不清楚你在这里是什么意思...谁在说崩溃?我对崩溃毫无兴趣。服务可以启动,停止,也许是意图服务,完成后它会自行停止...例如,问题是如何知道3分钟后它是否仍在运行。
Ewoks 2013年

1
给人以为还必须启动绑定服务的印象是不正确的。没有。绑定自动创建功能完全符合其要求。如果该服务尚未运行,它将创建(并因此“启动”)该服务。
Sreedevi J

57

一个小的补充是:

我的目标是知道服务是否正在运行,如果服务未运行,则实际上不会运行它。

调用bindService或调用服务可能捕获的意图不是一个好主意,因为如果服务未运行,它将启动服务。

因此,正如miracle2k建议的那样,最好的方法是在服务类中具有一个静态字段,以了解服务是否已启动。

为了使它更整洁,我建议通过非常懒惰的获取将服务转换为单例:也就是说,通过静态方法在所有单例实例上都没有实例化。您的服务/单例的静态getInstance方法仅返回单例的实例(如果已创建)。但这实际上并不会开始或实例化单例。该服务仅通过正常的服务启动方法启动。

然后,修改单例设计模式以将令人困惑的getInstance方法重命名为类似该isInstanceCreated() : boolean方法的方法将更加干净。

代码如下所示:

public class MyService extends Service
{
   private static MyService instance = null;

   public static boolean isInstanceCreated() {
      return instance != null;
   }//met

   @Override
   public void onCreate()
   {
      instance = this;
      ....
   }//met

   @Override
   public void onDestroy()
   {
      instance = null;
      ...
   }//met
}//class

这个解决方案很优雅,但是只有在您有权访问服务类并且仅对于类位于服务的应用程序/程序包时才有意义。如果您的类不在服务应用程序/程序包之外,则可以查询Pieter-Jan Van Robays强调的限制的ActivityManager。


32
这是有缺陷的。不保证可以调用onDestroy。
Pacerier'3

8
当系统内存不足时,您的服务将自动终止,而无需调用onDestroy,这就是为什么我说这是有缺陷的。
Pacerier,2012年

17
@Pacerier,但是如果系统终止了该进程,则实例标志仍将重置。我猜想当接收器下一次加载(系统终止服务后)时,静态标志“ instance”将重新创建为null。
汤姆(Tom)

2
至少比遍历isMyServiceRunning中的所有这些服务要好得多,如果在每次设备旋转时都完成,这真的会延迟工作:)
Gunnar Forsgren-Mobimation

1
您的实例变量不应声明为final,否则无法通过onCreate()或onDestroy()方法进行设置或将其设置为null。
k2col 2013年

27

您可以使用它(我还没有尝试过,但是我希望它能起作用):

if(startService(someIntent) != null) {
    Toast.makeText(getBaseContext(), "Service is already running", Toast.LENGTH_SHORT).show();
}
else {
    Toast.makeText(getBaseContext(), "There is no service running, starting service..", Toast.LENGTH_SHORT).show();
}

如果已经有运行中的服务,则startService方法将返回ComponentName对象。否则,将返回null。

请参见公共抽象ComponentName startService(意图服务)

我想这不像检查,因为它正在启动服务,因此您可以stopService(someIntent);在代码下添加。


11
不完全是文档所说的话。根据您的链接:“返回如果服务正在启动或已经在运行,则将返回已启动的实际服务的ComponentName;否则,如果服务不存在,则返回null。”
加百利

很好的想法...但是不适用于当前情况。
Code_Life 2012年

5
这是不正确的方法,因为当IDE触发时if(startService(someIntent) != null),它将进行检查,IsserviceRunning但也会播放新的服务。
Chintan Khetiya

如前所述,如果您在此控制后停止服务,将很方便解决此问题。但是,为什么不花钱就启动和停止服务呢?
Taner

6
这将启动服务,不是吗?只想检查服务状态而不是启动它...
Raptor 2014年

26
/**
 * Check if the service is Running 
 * @param serviceClass the class of the Service
 *
 * @return true if the service is running otherwise false
 */
public boolean checkServiceRunning(Class<?> serviceClass){
    ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE))
    {
        if (serviceClass.getName().equals(service.service.getClassName()))
        {
            return true;
        }
    }
    return false;
}

21

Android文档摘录:

sendBroadcast(Intent)一样,但是如果有任何Intent接收者,则此函数将阻塞并在返回之前立即分派它们。

认为这种黑客行为是“ ping”该行为Service。由于我们可以同步广播,因此可以在UI线程上同步广播并获取结果。

Service

@Override
public void onCreate() {
   LocalBroadcastManager
     .getInstance(this)
     .registerReceiver(new ServiceEchoReceiver(), new IntentFilter("ping"));
     //do not forget to deregister the receiver when the service is destroyed to avoid
     //any potential memory leaks 
}

private class ServiceEchoReceiver extends BroadcastReceiver {
    public void onReceive (Context context, Intent intent) {
      LocalBroadcastManager
         .getInstance(this)
         .sendBroadcastSync(new Intent("pong"));
    }
}

Activity

    bool serviceRunning = false;

    protected void onCreate (Bundle savedInstanceState){
        LocalBroadcastManager.getInstance(this).registerReceiver(pong, new IntentFilter("pong"));
        LocalBroadcastManager.getInstance(this).sendBroadcastSync(new Intent("ping"));
        if(!serviceRunning){
           //run the service
        }
    }

    private BroadcastReceiver pong = new BroadcastReceiver(){
        public void onReceive (Context context, Intent intent) {
          serviceRunning = true;   
        }
    }

当然,在许多应用程序中,胜利者是服务上设置为truein Service.onCreate()和to falsein 的服务上的静态布尔字段,Service.onDestroy()因为它要简单得多。


这是一个比公认的解决方案好得多的解决方案,该解决方案在Android终止该服务时会失败,因为全局变量方法仍会指示该服务在实际上不再运行时正在运行。这种同步的乒乓广播技巧实际上是检查服务是否有效的唯一可靠方法。仅凭它,您就可以简单地询问服务(如果有)。如果它回答,则该服务是活动的并且正在运行;如果不是,则该服务尚未以编程方式或由系统启动或已关闭以恢复内存。
Phoenix在

13

我对上述解决方案之一进行了一些修改,但传递了类而不是通用字符串名称,以确保比较来自同一方法的字符串 class.getName()

public class ServiceTools {
    private static String LOG_TAG = ServiceTools.class.getName();

    public static boolean isServiceRunning(Context context,Class<?> serviceClass){
        final ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
        final List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);

        for (RunningServiceInfo runningServiceInfo : services) {
            Log.d(Constants.TAG, String.format("Service:%s", runningServiceInfo.service.getClassName()));
            if (runningServiceInfo.service.getClassName().equals(serviceClass.getName())){
                return true;
            }
        }
        return false;
    }
}

然后

Boolean isServiceRunning = ServiceTools.isServiceRunning(
                    MainActivity.this.getApplicationContext(),
                    BackgroundIntentService.class);

更严格地说,您可以将类参数更改为Class<? extends Service>
–silentsudo

11

检查服务是否正在运行的正确方法是简单地询问它。在您的服务中实现一个BroadcastReceiver,以响应您的活动的ping。服务启动时注册BroadcastReceiver,服务销毁时取消注册。从您的活动(或任何组件)中,向服务发送本地广播意图,如果响应,您就知道它正在运行。请注意以下代码中ACTION_PING和ACTION_PONG之间的细微差别。

public class PingableService extends Service
{
    public static final String ACTION_PING = PingableService.class.getName() + ".PING";
    public static final String ACTION_PONG = PingableService.class.getName() + ".PONG";

    public int onStartCommand (Intent intent, int flags, int startId)
    {
        LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, new IntentFilter(ACTION_PING));
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy ()
    {
        LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
        super.onDestroy();
    }

    private BroadcastReceiver mReceiver = new BroadcastReceiver()
    {
        @Override
        public void onReceive (Context context, Intent intent)
        {
            if (intent.getAction().equals(ACTION_PING))
            {
                LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getApplicationContext());
                manager.sendBroadcast(new Intent(ACTION_PONG));
            }
        }
    };
}


public class MyActivity extends Activity
{
    private boolean isSvcRunning = false;

    @Override
    protected void onStart()
    {
        LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getApplicationContext());
        manager.registerReceiver(mReceiver, new IntentFilter(PingableService.ACTION_PONG));
        // the service will respond to this broadcast only if it's running
        manager.sendBroadcast(new Intent(PingableService.ACTION_PING));
        super.onStart();
    }

    @Override
    protected void onStop()
    {
        LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
        super.onStop();
    }

    protected BroadcastReceiver mReceiver = new BroadcastReceiver()
    {
        @Override
        public void onReceive (Context context, Intent intent)
        {
            // here you receive the response from the service
            if (intent.getAction().equals(PingableService.ACTION_PONG))
            {
                isSvcRunning = true;
            }
        }
    };
}

1
我实际上很喜欢这种方法。这是一个繁琐的代码,但始终可以使用。我看不到广播意图很快会被弃用:)
ShellDude

8

我只想在@Snicolas的答案中添加注释。以下步骤可用于检查通过/不通过调用停止服务onDestroy()

  1. onDestroy() 称为:转到设置->应用程序->运行服务->选择并停止您的服务。

  2. onDestroy()未调用:转到设置->应用程序->管理应用程序->选择并“强制停止”运行服务的应用程序。但是,由于您的应用程序在这里停止,因此肯定也将停止服务实例。

最后,我要提到的是,在那里提到的在单例类中使用静态变量的方法对我有效。


7

onDestroy 并不总是在服务中调用,因此这是没有用的!

例如:从Eclipse进行一次更改即可再次运行该应用程序。使用SIG强制退出该应用程序:9。


6

首先,您不要尝试使用ActivityManager来获得服务。(在这里讨论)

服务可以自己运行,可以绑定到活动,也可以两者都运行。检入Activity是否服务正在运行的方法是通过创建一个接口(扩展Binder),在该接口中声明Activity和Service都可以理解的方法。您可以通过在声明例如“ isServiceRunning()”的地方创建自己的接口来实现。然后,您可以将Activity绑定到Service,运行方法isServiceRunning(),Service将检查自身是否正在运行,并将布尔值返回给Activity。

您还可以使用此方法停止服务或以其他方式与其交互。

我使用本教程来学习如何在应用程序中实现此方案。


3
该讨论在'12 / 26/07'进行。要么是今年7月(即将来),要么是Android尚未公开。无论哪种方式,我都不相信。
汤姆

这种讨论是从12月26日,2007年他们在讨论一个预发布版本,我认为(developer.android.com/sdk/OLD_RELEASENOTES.html#m3-rc37a它发布于2007年12月14日)
ingh.am

6

同样,如果人们使用未决的意图(例如使用AlarmManager:,人们可能会发现更干净的另一种选择):

public static boolean isRunning(Class<? extends Service> serviceClass) {
    final Intent intent = new Intent(context, serviceClass);
    return (PendingIntent.getService(context, CODE, intent, PendingIntent.FLAG_NO_CREATE) != null);
}

CODE您在班级中私下定义的常量是哪里,以标识与您的服务关联的未决意图。


1
合并或更新您以前的答案。请避免在每个帖子中发布多个答案。
ChuongPham

是否可以扩展此答案,即如何将CODE的值与服务相关联?
Dave Nottage

在哪里获取上下文?
罗勒

6

以下是涵盖所有内容的优雅技巧Ifs。这仅适用于本地服务。

    public final class AService extends Service {

        private static AService mInstance = null;

        public static boolean isServiceCreated() {
            try {
                // If instance was not cleared but the service was destroyed an Exception will be thrown
                return mInstance != null && mInstance.ping();
            } catch (NullPointerException e) {
                // destroyed/not-started
                return false;
            }
        }

        /**
         * Simply returns true. If the service is still active, this method will be accessible.
         * @return
         */
        private boolean ping() {
            return true;
        }

        @Override
        public void onCreate() {
            mInstance = this;
        }

        @Override
        public void onDestroy() {
            mInstance = null;
        }
    }

然后再:

    if(AService.isServiceCreated()){
        ...
    }else{
        startService(...);
    }

唯一的问题是该服务是否为粘性服务,并会自行重启。服务再次启动后,对isServiceCreated()的调用将返回false,因为mInstance将为null。
Mira_Cole

1
当服务重新启动时,会不会调用onCreate吗?
TheRealChx101 '18

6

Xamarin C#版本:

private bool isMyServiceRunning(System.Type cls)
{
    ActivityManager manager = (ActivityManager)GetSystemService(Context.ActivityService);

    foreach (var service in manager.GetRunningServices(int.MaxValue)) {
        if (service.Service.ClassName.Equals(Java.Lang.Class.FromType(cls).CanonicalName)) {
            return true;
        }
    }
    return false;
}

您需要的“上下文” GetSystemService
测试

5

对于此处给出的用例,我们可以简单地利用stopService()方法的返回值。它返回true是否存在指定的服务并将其杀死。否则它返回false。因此,如果结果是false可以确保当前服务已停止,则可以重新启动服务。:)这将是更好,如果你看看这个


5

另一种使用kotlin的方法。受其他用户启发

fun isMyServiceRunning(serviceClass: Class<*>): Boolean {
    val manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    return manager.getRunningServices(Integer.MAX_VALUE)
            .any { it.service.className == serviceClass.name }
}

作为kotlin扩展

fun Context.isMyServiceRunning(serviceClass: Class<*>): Boolean {
    val manager = this.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    return manager.getRunningServices(Integer.MAX_VALUE)
            .any { it.service.className == serviceClass.name }
}

用法

context.isMyServiceRunning(MyService::class.java)

4

在kotlin中,您可以在伴随对象中添加布尔变量,并从任何所需的类中检查其值:

companion object{
     var isRuning = false

}

创建和销毁服务时更改其值

 override fun onCreate() {
        super.onCreate()
        isRuning = true
    }

override fun onDestroy() {
    super.onDestroy()
    isRuning = false
    }

3

在服务子类中,使用静态布尔值获取服务的状态,如下所示。

MyService.kt

class MyService : Service() {
    override fun onCreate() {
        super.onCreate()
        isServiceStarted = true
    }
    override fun onDestroy() {
        super.onDestroy()
        isServiceStarted = false
    }
    companion object {
        var isServiceStarted = false
    }
}

MainActivity.kt

class MainActivity : AppCompatActivity(){
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val serviceStarted = FileObserverService.isServiceStarted
        if (!serviceStarted) {
            val startFileObserverService = Intent(this, FileObserverService::class.java)
            ContextCompat.startForegroundService(this, startFileObserverService)
        }
    }
}

3

对于kotlin,可以使用以下代码。

fun isMyServiceRunning(calssObj: Class<SERVICE_CALL_NAME>): Boolean {
    val manager = requireActivity().getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
        if (calssObj.getName().equals(service.service.getClassName())) {
            return true
        }
    }
    return false
}

对于编写测试,这是一个很好的答案,因为您可以在不更改工作代码的情况下使用它。
罗伯特·利伯托雷特

2

geekQ的响应但在Kotlin类中。谢谢geekQ

fun isMyServiceRunning(serviceClass : Class<*> ) : Boolean{
    var manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
        if (serviceClass.name.equals(service.service.className)) {
            return true
        }
    }
    return false
}

通话

isMyServiceRunning(NewService::class.java)

6
ActivityManager.getRunningServices自Android O以来已弃用
Daniel Shatz

1

可以有多个具有相同类名的服务。

我刚刚创建了两个应用程序。第一个应用的软件包名称为com.example.mock。我lorem在应用程序中创建了一个子程序包,并创建了一个服务Mock2Service。所以它的全名是com.example.mock.lorem.Mock2Service

然后,我创建了第二个应用程序和名为的服务Mock2Service。第二个应用的程序包名称为com.example.mock.lorem。服务的标准名称是com.example.mock.lorem.Mock2Service也为。

这是我的logcat输出。

03-27 12:02:19.985: D/TAG(32155): Mock-01: com.example.mock.lorem.Mock2Service
03-27 12:02:33.755: D/TAG(32277): Mock-02: com.example.mock.lorem.Mock2Service

更好的方法是比较ComponentName,因为实例equals()ComponentName两个包名和类名进行比较。而且,设备上不能安装两个具有相同程序包名称的应用程序。

的equals()方法ComponentName

@Override
public boolean equals(Object obj) {
    try {
        if (obj != null) {
            ComponentName other = (ComponentName)obj;
            // Note: no null checks, because mPackage and mClass can
            // never be null.
            return mPackage.equals(other.mPackage)
                    && mClass.equals(other.mClass);
        }
    } catch (ClassCastException e) {
    }
    return false;
}

组件名称


1

请使用此代码。

if (isMyServiceRunning(MainActivity.this, xyzService.class)) { // Service class name
    // Service running
} else {
    // Service Stop
}


public static boolean isMyServiceRunning(Activity activity, Class<?> serviceClass) {
        ActivityManager manager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (serviceClass.getName().equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }

0

这更适用于Intent Service调试,因为它们会生成线程,但也可能适用于常规服务。我发现这个线程归功于Binging

就我而言,我与调试器一起玩耍并找到了线程视图。看起来有点像MS Word中的项目符号图标。无论如何,您不必处于调试器模式即可使用它。单击该过程,然后单击该按钮。任何Intent Services都会在运行时显示,至少在模拟器上会显示。


0

如果服务属于另一个进程或APK,请使用基于ActivityManager的解决方案。

如果您有权访问其源代码,只需使用基于静态字段的解决方案。但是我建议使用Date对象,而不是使用布尔值。在服务运行时,只需将其值更新为“ now”,完成后将其设置为null。从活动中,您可以检查其空值或日期是否过旧,这表示该活动未运行。

您还可以从您的服务发送广播通知,指示正在运行的其他信息包括进度。


0

在TheServiceClass内部定义:

 public static Boolean serviceRunning = false;

然后在onStartCommand(...)

 public int onStartCommand(Intent intent, int flags, int startId) {

    serviceRunning = true;
    ...
}

 @Override
public void onDestroy()
{
    serviceRunning = false;

} 

然后,if(TheServiceClass.serviceRunning == true)从任何班级打电话。


4
如果您的服务被Android杀死,则无法使用此功能。
海森堡

@海森堡我刚刚经历了自己。你知道为什么不吗?
蒂姆(Tim)

@Heisenberg,当我的应用程序被操作系统终止时,服务会重新启动并将静态布尔值设置为true,但是一旦获取,它将报告为false
Tim

如果您打电话给我,那是行不通的stopService。至少用于Intent服务。onDestroy()将立即被调用,但onHandleIntent()仍会运行
serggl '16

1
@Heisenberg不会由于内存不足而终止服务还意味着终止进程?
Android开发人员

0

简单使用bind with不要创建自动 -请参见ps。并更新...

public abstract class Context {

 ... 

  /*
  * @return {true} If you have successfully bound to the service, 
  *  {false} is returned if the connection is not made 
  *  so you will not receive the service object.
  */
  public abstract boolean bindService(@RequiresPermission Intent service,
        @NonNull ServiceConnection conn, @BindServiceFlags int flags);

例如:

    Intent bindIntent = new Intent(context, Class<Service>);
    boolean bindResult = context.bindService(bindIntent, ServiceConnection, 0);

为什么不使用?getRunningServices()

List<ActivityManager.RunningServiceInfo> getRunningServices (int maxNum)
Return a list of the services that are currently running.

注意:此方法仅用于调试或实现服务管理类型的用户界面。


ps。android文档具有误导性,我已在Google跟踪器上打开了一个问题,以消除任何疑问:

https://issuetracker.google.com/issues/68908332

如我们所见,绑定服务实际上是通过ActivityManager绑定器通过服务缓存绑定器来调用事务的-我跟踪了负责绑定的服务,但是如我们所见,绑定的结果是:

int res = ActivityManagerNative.getDefault().bindService(...);
return res != 0;

通过活页夹进行交易:

ServiceManager.getService("activity");

下一个:

  public static IBinder getService(String name) {
    try {
        IBinder service = sCache.get(name);
        if (service != null) {
            return service;
        } else {
            return getIServiceManager().getService(name);

这是通过以下方法在ActivityThread中设置的:

 public final void bindApplication(...) {

        if (services != null) {
            // Setup the service cache in the ServiceManager
            ServiceManager.initServiceCache(services);
        }

这在ActivityManagerService的方法中被调用:

 private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
    ...
    thread.bindApplication(... , getCommonServicesLocked(),...)

然后:

 private HashMap<String, IBinder> getCommonServicesLocked() {

但是没有“活动”窗口包和警报。

所以我们需要回电话:

 return getIServiceManager().getService(name);

    sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());

这可以通过以下方式致电:

    mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);

这导致 :

BinderInternal.getContextObject()

这是本机方法。

  /**
     * Return the global "context object" of the system.  This is usually
     * an implementation of IServiceManager, which you can use to find
     * other services.
     */
    public static final native IBinder getContextObject();

我现在没有时间在c中挖洞,所以直到我剖析了剩余的呼叫之后,我才暂停回答。

但是检查服务是否正在运行的最佳方法是创建绑定(如果未创建绑定,则服务不存在)-并通过绑定查询服务的状态(在其状态上使用存储的内部标志)。

更新23.06.2018

我发现那些有趣:

/**
 * Provide a binder to an already-bound service.  This method is synchronous
 * and will not start the target service if it is not present, so it is safe
 * to call from {@link #onReceive}.
 *
 * For peekService() to return a non null {@link android.os.IBinder} interface
 * the service must have published it before. In other words some component
 * must have called {@link android.content.Context#bindService(Intent, ServiceConnection, int)} on it.
 *
 * @param myContext The Context that had been passed to {@link #onReceive(Context, Intent)}
 * @param service Identifies the already-bound service you wish to use. See
 * {@link android.content.Context#bindService(Intent, ServiceConnection, int)}
 * for more information.
 */
public IBinder peekService(Context myContext, Intent service) {
    IActivityManager am = ActivityManager.getService();
    IBinder binder = null;
    try {
        service.prepareToLeaveProcess(myContext);
        binder = am.peekService(service, service.resolveTypeIfNeeded(
                myContext.getContentResolver()), myContext.getOpPackageName());
    } catch (RemoteException e) {
    }
    return binder;
}

简而言之 :)

“为已经绑定的服务提供绑定程序。此方法是同步的,如果不存在,则不会启动目标服务。”

公共IBinder peekService(意图服务,字符串resolveType,字符串callingPackage)抛出RemoteException;

*

public static IBinder peekService(IBinder remote, Intent service, String resolvedType)
             throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken("android.app.IActivityManager");
    service.writeToParcel(data, 0);
    data.writeString(resolvedType);
    remote.transact(android.os.IBinder.FIRST_CALL_TRANSACTION+84, data, reply, 0);
    reply.readException();
    IBinder binder = reply.readStrongBinder();
    reply.recycle();
    data.recycle();
    return binder;
}

*


如果服务未运行,则bindResult(bindService方法的返回值)不会为false。
Shangeeth Sivan

0

我的Kotlin转换的ActivityManager::getRunningServices基础答案。将此功能放在活动中-

private fun isMyServiceRunning(serviceClass: Class<out Service>) =
    (getSystemService(ACTIVITY_SERVICE) as ActivityManager)
        .getRunningServices(Int.MAX_VALUE)
        ?.map { it.service.className }
        ?.contains(serviceClass.name) ?: false

-2

您可以使用Android开发人员选项中的此选项来查看您的服务是否仍在后台运行。

1. Open Settings in your Android device.
2. Find Developer Options.
3. Find Running Services option.
4. Find your app icon.
5. You will then see all the service that belongs to your app running in the background.

-5

放轻松,伙计们... :)

我认为最合适的解决方案是SharedPreferences在服务是否运行的情况下保留键值对。

逻辑很直;在您的服务级别中的任何所需位置;放置一个布尔值,该值将为您提供有关服务是否正在运行的标志。然后在应用程序中的任何位置读取此值。

我在应用程序中使用的示例代码如下:

在服务类(音频流的服务)中,当服务启动时,我将执行以下代码;

private void updatePlayerStatus(boolean isRadioPlaying)
{
        SharedPreferences sharedPref = this.getSharedPreferences(getString(R.string.str_shared_file_name), Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPref.edit();
        editor.putBoolean(getString(R.string.str_shared_file_radio_status_key), isRadioPlaying);
        editor.commit();
}

然后,在我的应用程序的任何活动中,我将通过以下代码检查服务的状态;

private boolean isRadioRunning() {
        SharedPreferences sharedPref = this.getSharedPreferences(getString(R.string.str_shared_file_name), Context.MODE_PRIVATE);

        return sharedPref.getBoolean(getString(R.string.str_shared_file_radio_status_key), false);
}

没有特殊权限,没有循环...简单的方法,干净的解决方案:)

如果您需要其他信息,请参阅链接

希望这可以帮助。


19
只有这样,当他们
终止

当杀死服务时,onDestroy()服务将被触发,并且有可能更新其状态
Jongz Puangput 2015年

5
@JongzPuangput,onDestroy在服务被终止时并不总是被调用。例如,我看到我的服务在内存不足的情况下onDestroy被杀死而没有被调用。
2015年

@Sam然后会叫什么?
Ruchir Baronia'2

2
@RuchirBaronia据我记得,当您的物品被杀死时,您根本不会收到通知。我认为Android旨在根据需要杀死应用程序,并且应将应用程序设计为在不通知的情况下随时被杀死。
山姆
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.