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

我想要一个切换服务状态的Android活动——它让我打开它,如果它是关闭的,如果它是关闭的。


当前回答

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

例如:只需要对Eclipse做一点更改就可以再次运行应用程序。使用SIG: 9强制退出应用程序。

其他回答

下面是一个优雅的技巧,涵盖了所有的假设。这只适用于本地服务。

    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(...);
    }

对于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
}

一个小补语是:

我的目标是知道一个服务是否在运行,如果它没有运行。

调用bindService或调用一个可以被服务捕获的意图不是一个好主意,因为它会在服务未运行时启动服务。

因此,正如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。

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

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

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

我刚刚创建了两个应用程序。第一个应用程序的包名是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实例,因为ComponentName的equals()比较包名和类名。一个设备上不能安装两个包名相同的应用程序。

ComponentName的equals()方法。

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

ComponentName