当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何检查服务是否在Android上运行?》经验,为你挑选了16个好方法。

如何检查后台服务(在Android上)是否正在运行?

我想要一个能够切换服务状态的Android活动 - 它可以让我打开它,如果它打开则关闭.



1> geekQ..:

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

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"列.


谢谢你的解决方案.我想补充一点:相反"com.example.MyService"使用MyService.class.getName()更优雅
不,这不是正确的答案,因为它也写在文档中:"注意:此方法仅用于调试或实现服务管理类型用户界面." 它不适用于控制流程!
启动**Android O**,不推荐使用`getRunningServices`.此答案需要更新较新版本.
人们发现要检查服务器是否正在运行所有这些都很优雅?
就个人而言,我选择使用静态字段.虽然使用getRunningServices()是一个更强大的解决方案,但我相信这两个解决方案在稳健性和效率/简单性之间进行权衡.如果您需要经常检查服务是否正在运行,那么循环使用30多个正在运行的服务并不是很理想.可能通过try/catch块或使用START_STICKY来处理系统销毁服务的罕见情况.
我不鼓励使用这个解决方案.对于Android L [他们正在删除](https://developer.android.com/preview/api-overview.html#Behaviors)ActivityManager.getRecentTasks(),它在文档中有相同的注释.所以要警告!
此代码不正确/不完整.它还需要检查包名称,因为目前您可能会从其他包而不是您自己的包中找到服务.
-1.这种方法并不是真正可持续的.它不适用于Android KitKat.
这似乎找到了已停止的服务以及正在运行的服务.也许`return service.started;`改进`return true;`?
不应该是`<?扩展服务>`所以用错误的参数调用它更难?
@ poring91从**O**开始,'getRunningServices`不再适用于**第三方**应用程序.为了向后兼容,它仍然会返回调用方自己的服务**.

2> miracle2k..:

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

编辑(记录):

这是hackbod提出的解决方案:

如果您的客户端和服务器代码是同一个.apk的一部分,并且您使用具体的Intent(指定确切的服务类的那个)绑定到该服务,那么您可以简单地让您的服务在运行时设置一个全局变量你的客户可以检查.

我们故意没有API来检查服务是否正在运行,因为几乎没有失败,当你想要做类似的事情时,你最终会遇到代码中的竞争条件.


@Pacerier,您引用的解决方案需要启动服务,我认为最灵活的解决方案应该允许您在不启动服务的情况下检查服务是否正在运行.
当应用程序被杀死时,它已启动的服务也被杀死,但服务的`onDestroy()`未被调用.因此,在这种情况下无法更新静态变量,从而导致行为不一致.
如果系统停止服务,您如何检测并切换变量呢?
@faizal,本地服务不是一个单独的进程,所以如果服务被杀死,那么app也会被杀死.
@faizal静态变量是否也不会被重新初始化,从而将其设置回默认值,表明服务不再运行?
@faizal好的,在这种情况下会调用服务上的onDestroy()吗?

3> Kevin Parker..:

得到它了!

必须要求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 services = activityManager.getRunningServices(Integer.MAX_VALUE);

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


对不起,但我需要说这是超级愚蠢的答案.为什么它超级明显?!
不清楚你的意思在哪里......谁在谈论崩溃?!崩溃它我并不感兴趣.服务可以启动,停止,也许它是意图服务,当它完成时它将自动停止...问题是如何知道它是否仍然在3分钟后运行.

4> Snicolas..:

一个小补充是:

我的目标是知道一个服务正在运行,如果没有运行它没有实际运行它.

调用bindService或调用可以被服务捕获的intent并不是一个好主意,因为如果它没有运行它将启动服务.

因此,正如miracle2k建议的那样,最好的方法是在服务类中使用静态字段来了解服务是否已经启动.

为了使它更干净,我建议使用一个非常非常懒的读取来转换服务:也就是说,通过静态方法没有实例化所有单例实例.service/singleton的静态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.


这是有缺陷的.不保证会调用onDestroy.
@Pacerier,但如果系统终止进程,则实例标志仍将被重置.我猜测当接收器下一次加载(系统杀死服务后)静态标志'instance'将被重新创建为null.
当系统内存不足时,您的服务将自动终止而无需调用onDestroy,这就是为什么我说这是有缺陷的.
至少比在isMyServiceRunning中迭代所有这些服务更好,如果在每个设备轮换上完成,这实际上会延迟这些服务:)

5> Keenan Gebze..:

你可以使用它(我还没试过,但我希望这有效):

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);在代码下添加.


不完全是文档所说的.根据您的链接:"返回如果服务正在启动或已在运行,则返回已启动的实际服务的ComponentName;否则,如果该服务不存在,则返回null."
这将启动服务,不是吗?只是想检查服务的状态而不是启动它...
它不正确的方式,因为当IDE触发`if(startService(someIntent)!= null)`时,它会检查`IsserviceRunning`但是它也会播放新服务.

6> J.R..:
/**
 * 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;
}



7> peterchaula..:

这是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;   
        }
    }



8> loretoparisi..:

我稍微修改了上面提到的解决方案之一,但传递了类而不是通用的字符串名称,以确保比较来自同一方法的字符串 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 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);



9> Paul..:

我只想在@Snicolas的答案中添加一个注释.以下步骤可用于在有/无呼叫的情况下检查停止服务onDestroy().

    onDestroy() 被叫:转到设置 - >应用程序 - >运行服务 - >选择并停止服务.

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

最后,我想提一下,在单例类中使用静态变量提到的方法对我有用.



10> Kevin Parker..:

onDestroy 并不总是在服务中调用,所以这是没用的!

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



11> Ben H..:

检查服务是否正在运行的正确方法是简单地询问它.在您的服务中实现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;
            }
        }
    };
}



12> 小智..:

首先,您不会尝试使用ActivityManager来访问服务.(在这里讨论)

服务可以独立运行,绑定到一个Activity或两者都绑定.如果您的服务正在运行,则检查Activity的方法是创建一个接口(扩展Binder),您可以在其中声明Activity和Service都能理解的方法.您可以通过在声明"isServiceRunning()"的位置创建自己的接口来完成此操作.然后,您可以将Activity绑定到您的Service,运行方法isServiceRunning(),如果它正在运行,Service将自行检查并为您的Activity返回一个布尔值.

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

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


那次讨论发生在'12/26/07'.无论是今年7月(即未来),还是Android之前都是公开的.这两种方式都让我不相信它.

13> Nima..:

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;
}



14> TheRealChx10..:

以下是涵盖所有内容的优雅技巧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(...);
    }



15> Rahul Raveen..:

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



16> Snicolas..:

同样,如果人们使用未决的意图(例如使用AlarmManager:,人们可能会发现更清洁)

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

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

推荐阅读
郑谊099_448
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有