Как проверить, работает ли фоновая служба?
Я хочу, чтобы активность Android изменяла состояние службы - она позволяла мне включать его, если он выключен, и выключен, если он включен.
getRunningTasks()
, вероятно, так и будет.
Как проверить, работает ли фоновая служба?
Я хочу, чтобы активность Android изменяла состояние службы - она позволяла мне включать его, если он выключен, и выключен, если он включен.
getRunningTasks()
, вероятно, так и будет.
Ответы:
У меня была такая же проблема не так давно. Так как мой сервис был локальным, я просто использовал статическое поле в классе сервиса для переключения состояния, как описано здесь hackbod
РЕДАКТИРОВАТЬ (для записи):
Вот решение, предложенное hackbod:
Если ваш клиентский и серверный код является частью одного и того же .apk, и вы привязываетесь к сервису с конкретным намерением (которое указывает точный класс сервиса), то вы можете просто сделать так, чтобы ваш сервис установил глобальную переменную, когда он выполняет Ваш клиент может проверить.
У нас намеренно нет API, чтобы проверить, работает ли служба, потому что, почти всегда, когда вы хотите сделать что-то подобное, вы сталкиваетесь с условиями гонки в своем коде.
onDestroy()
вызывается. Таким образом, статическая переменная не может быть обновлена в таком сценарии, что приводит к противоречивому поведению.
Я использую следующее изнутри деятельности:
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 решает убить ваш процесс или какой из упомянутых обратных вызовов вызван или нет. Обратите внимание на столбец «killable» в таблице событий жизненного цикла в документации Android.
getRunningServices
является устаревшим. Этот ответ требует обновления для более новой версии.
Понял!
Вы ДОЛЖНЫ призвать 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;
}
}
Небольшое дополнение это:
Моя цель - знать, запущен ли сервис без его фактического запуска, если он не запущен.
Вызов 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
Это элегантное решение, но оно актуально только в том случае, если у вас есть доступ к классу обслуживания и только для классов, кроме приложения / пакета службы. Если ваши занятия находятся за пределами приложения / пакета службы, вы можете запросить ActivityManager с ограничениями, подчеркнутыми Питером-Яном Ван Робайсом.
Вы можете использовать это (я еще не пробовал это, но я надеюсь, что это работает):
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, если уже есть запущенная служба. Если нет, ноль будет возвращен.
Смотрите публичный абстрактный ComponentName startService (сервис Intent) .
Я думаю, это не похоже на проверку, потому что она запускает службу, поэтому вы можете добавить ее stopService(someIntent);
под код.
if(startService(someIntent) != null)
это проверит, IsserviceRunning
но это также сыграет новый сервис.
/**
* 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;
}
Выдержка из документов Android :
Подобно sendBroadcast (Intent) , но если для Intent есть приемники, эта функция заблокирует их и немедленно отправит перед возвратом.
Думайте об этом взломе как о "пингующем"Service
. Поскольку мы можем транслировать синхронно, мы можем транслировать и получать результат синхронно в потоке пользовательского интерфейса.
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;
}
}
Конечно, во многих приложениях победителем является статическое логическое поле в сервисе, для которого задано значение true
in Service.onCreate()
и false
in, Service.onDestroy()
потому что это намного проще.
Я немного изменил одно из представленных выше решений, но передал класс вместо общего имени строки, чтобы быть уверенным в сравнении строк, исходящих из одного и того же метода. 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>
Правильный способ проверить, работает ли служба, - просто спросить ее. Внедрите в вашу службу BroadcastReceiver, который отвечает на запросы вашей работы. Зарегистрируйте 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;
}
}
};
}
Я просто хочу добавить примечание к ответу @Snicolas. Следующие шаги могут быть использованы для проверки остановки службы с / без вызова onDestroy()
.
onDestroy()
Вызов: перейдите в Настройки -> Приложение -> Запущенные сервисы -> Выберите и остановите сервис.
onDestroy()
не вызывается: выберите «Настройки» -> «Приложение» -> «Управление приложениями» -> выберите и «принудительно остановите» приложение, в котором запущена ваша служба. Однако, поскольку ваше приложение здесь остановлено, экземпляры службы также будут остановлены.
Наконец, я хотел бы отметить, что упомянутый там подход с использованием статической переменной в синглтон-классе работает для меня.
onDestroy
не всегда вызывается в сервисе, так что это бесполезно!
Например: просто запустите приложение еще раз с одним изменением из Eclipse. Приложение принудительно закрывается с помощью SIG: 9.
Прежде всего, вы не должны пытаться связаться с сервисом с помощью ActivityManager. (Обсуждается здесь )
Службы могут работать самостоятельно, быть привязаны к действию или к обоим. Чтобы проверить в Деятельности, работает ли ваша Служба или нет, нужно создать интерфейс (расширяющий Binder), в котором вы объявляете методы, понятные как Службе, так и Службе. Вы можете сделать это, создав собственный интерфейс, где вы объявляете, например, «isServiceRunning ()». Затем вы можете привязать свою активность к своей службе, запустить метод isServiceRunning (), служба проверит себя, работает ли она или нет, и вернет логическое значение вашей активности.
Вы также можете использовать этот метод, чтобы остановить службу или взаимодействовать с ней другим способом.
Я использовал этот учебник, чтобы узнать, как реализовать этот сценарий в моем приложении.
Опять же, еще одна альтернатива, которую люди могут найти чище, если они используют ожидающие намерения (например, с помощью 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
константа, которую вы определяете в частном порядке в своем классе, чтобы определить ожидающие намерения, связанные с вашим сервисом.
Ниже приведен элегантный хак, который охватывает все 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(...);
}
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
.
Для приведенного здесь варианта использования мы можем просто использовать stopService()
возвращаемое значение метода. Он возвращает, true
если существует указанный сервис, и он убит. Остальное возвращается false
. Таким образом, вы можете перезапустить службу, если в результате false
получится уверенность, что текущая служба была остановлена. :) Было бы лучше, если вы посмотрите на это .
Другой подход с использованием котлина. Вдохновленные другими пользователями ответы
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 }
}
Как расширение котлин
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)
В kotlin вы можете добавить логическую переменную в объект-компаньон и проверить ее значение из любого класса, который вы хотите:
companion object{
var isRuning = false
}
Измените это значение, когда служба создана и уничтожена
override fun onCreate() {
super.onCreate()
isRuning = true
}
override fun onDestroy() {
super.onDestroy()
isRuning = false
}
В вашем подклассе службы используйте статическое логическое значение, чтобы получить состояние службы, как показано ниже.
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)
}
}
}
Для 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
}
Ответ 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)
ActivityManager.getRunningServices
устарела с Android O
Может быть несколько служб с одинаковым именем класса.
Я только что создал два приложения. Имя пакета первого приложения 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;
}
Пожалуйста, используйте этот код.
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;
}
Это в большей степени относится к отладке Intent Service, поскольку они порождают поток, но могут работать и для обычных сервисов. Я нашел эту тему благодаря Binging
В моем случае я поиграл с отладчиком и нашел представление потока. Это выглядит как значок маркера в MS Word. В любом случае, вам не нужно находиться в режиме отладчика, чтобы использовать его. Нажмите на процесс и нажмите на эту кнопку. Любые Intent Services будут отображаться во время работы, по крайней мере, на эмуляторе.
Если служба принадлежит другому процессу или APK, используйте решение на основе ActivityManager.
Если у вас есть доступ к его источнику, просто используйте решение на основе статического поля. Но вместо использования логического значения я бы предложил использовать объект Date. Пока служба работает, просто измените ее значение на «сейчас», а когда оно завершится, установите значение «ноль». Из действия вы можете проверить, является ли его ноль или дата слишком старой, что будет означать, что она не запущена.
Вы также можете отправить широковещательное уведомление от вашего сервиса, указывающее, что он работает вместе с дополнительной информацией, такой как прогресс
Внутри 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)
из любого класса.
stopService
. По крайней мере, для услуг Intent. onDestroy()
будет вызван немедленно, но onHandleIntent()
все еще будет запущен
простое использование связать с не создавать авто - см. пс. и обновить ...
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.
Примечание: этот метод предназначен только для отладки или реализации пользовательских интерфейсов типа управления услугами.
пс. Документация Android вводит в заблуждение. Я открыл проблему на Google Tracker, чтобы устранить любые сомнения:
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();
у меня сейчас нет времени копаться в с, так что пока я не проанализирую покой, я приостановлю свой ответ.
но лучший способ проверить, работает ли сервис это создать привязку (если привязка не создана, служба не существует) - и запросить службу о ее состоянии через привязку (используя хранимый внутренний флаг для этого состояния).
я нашел эти интересные:
/**
* 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;
}
короче говоря :)
«Предоставьте привязку для уже связанной службы. Этот метод является синхронным и не запускает целевую службу, если она отсутствует».
public IBinder peekService (Служба намерений, String resolvedType, String callPackage) выдает 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;
}
*
Мой 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
Вы можете использовать эту опцию из опций Android Developer, чтобы увидеть, работает ли ваша служба в фоновом режиме.
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.
Полегче, ребята ... :)
Я думаю, что наиболее подходящим решением является удержание пары ключ-значение в 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);
}
Никаких специальных разрешений, никаких петель ... Простой способ, чистое решение :)
Если вам нужна дополнительная информация, пожалуйста, обратитесь по ссылке
Надеюсь это поможет.
onDestroy
не всегда вызывается, когда служба убита. Например, я видел, как мои службы убивали в ситуациях с нехваткой памяти без onDestroy
вызова.