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

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


当前回答

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

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

其他回答

摘自Android文档:

比如sendBroadcast(Intent),但是如果有任何接收器 这个函数将阻塞并立即分发它们 返回之前。

你可以把这次入侵看成是"ping "服务。因为我们可以同步广播,所以我们可以在UI线程上同步广播并获得结果。

服务

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

活动

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

当然,在许多应用程序中,赢家是服务上的静态布尔字段,在service . oncreate()中设置为true,在service . ondestroy()中设置为false,因为它要简单得多。

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

我从一个活动内部使用以下:

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事件或binder或静态变量的方法都不会可靠地工作,因为作为开发人员,你永远不知道Android何时决定杀死你的进程,或者调用哪些提到的回调。请注意Android文档中生命周期事件表中的“killable”列。

这更适用于Intent Service调试,因为它们会生成一个线程,但也适用于常规服务。我找到这个线程感谢宾

在我的例子中,我摆弄了调试器并找到了线程视图。它看起来有点像微软Word里的项目符号图标。无论如何,您不必在调试器模式下使用它。单击该流程并单击该按钮。任何Intent服务都会在运行时显示出来,至少在模拟器上是这样。

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