Як перевірити, чи працює служба на Android?


936

Як перевірити, чи працює фонова служба?

Я хочу активувати Android, що перемикає стан сервісу - він дозволяє мені його включати, якщо він вимкнений і вимкнений, якщо він увімкнено.



17
правильну відповідь нижче , а не один відзначений: stackoverflow.com/a/5921190/2369122
toidiu

1
@toidiu Якщо це ще не було задумано getRunningTasks(), мабуть, так і буде.
Кевін Крумвіеде

за допомогою функції getSystemService () ви можете отримати всі запущені служби. перегляньте його і перевірте, чи існує ваша послуга. У цьому списку ви можете побачити невеликий зразок wiki.workassis.com/android-check-the-service-is-running
Bikesh M

Відповіді:


292

У мене була така ж проблема недавно. Оскільки моя служба була локальною, я закінчив просто використовувати статичне поле в класі обслуговування для переключення стану, як описано тут hackbod

EDIT (для запису):

Ось рішення, запропоноване hackbod:

Якщо ваш клієнтський і серверний код є одним і тим же .apk і ви зобов’язуєтесь до служби конкретним наміром (той, який визначає точний клас обслуговування), тоді ви можете просто встановити службу глобальною змінною, коли вона працює, ваш клієнт може перевірити.

Ми навмисно не маємо API, щоб перевірити, чи працює служба, тому що, майже безвідмовно, коли ви хочете зробити щось подібне, ви в кінцевому підсумку перебуваєте в гоночних умовах.


27
@Pacerier, рішення, на яке ви посилаєтесь, вимагає запуску послуги, і я думаю, що найкраще гнучке рішення повинно дозволяти вам перевірити, чи працює служба без її запуску.
Том

17
Що робити, якщо система зупиняється системою, як ви її виявляєте та перемикаєте змінну?
jmng

23
Коли програма вбита, служба, яку вона запустила, також вбивається, але служба onDestroy()не викликається. Тож статична змінна не може бути оновлена ​​в такому сценарії, що призводить до непослідовної поведінки.
фазал

5
@faizal Чи не буде статична змінна також бути повторно ініціалізована, таким чином, повертаючи її до значення за замовчуванням, яке вказує, що служба більше не працює?
PabloC

12
@faizal, локальна служба - це не окремий процес, тому, якщо сервіс вбитий, програма також вбиватиме.
Північ

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.


85
Дякую за це рішення. Я хотів би додати: Натомість "com.example.MyService" більш елегантно використовувати MyService.class.getName ()
peter.bartos

10
Особисто я пішов із використанням статичного поля. Хоча використання getRunningServices () є більш надійним рішенням, я вважаю, що в цих двох рішеннях є компроміс між надійністю та ефективністю / простотою. Якщо вам потрібно часто перевіряти, чи працює служба, прокручування через потенційно 30+ запущених служб не дуже ідеально. Рідкісний випадок сервісу, знищеного системою, може бути оброблений, можливо, блоком спробу / лову або за допомогою START_STICKY.
robguinness

80
Ні, це не правильна відповідь, оскільки це також написано в документах: "Примітка. Цей метод призначений лише для налагодження або реалізації користувальницьких інтерфейсів типу управління службою." Це не призначено для контролю потоку!
1212

40
Люди вважають його елегантним, щоб пройти все це, щоб перевірити, чи працює сервер?
Rui Marques

79
Запуск Android O , 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

1
Неправильно створювати враження, що також потрібно запускати пов'язану службу. НІ. Прив'язка автоматичного створення робить саме те, що написано. Він створить (і, отже, "запустить" службу, якщо служба ще не працює.
Sreedevi J

57

Невелике доповнення:

Моя мета - дізнатися, чим надалі служба працює без її фактичного запуску, якщо вона не працює.

Виклик bindService або виклик наміру, який може бути спійманий службою, не є гарною ідеєю, оскільки він запустить службу, якщо вона не працює.

Отже, як запропонував miracle2k, найкраще - стати статичне поле в класі обслуговування, щоб знати, була послуга запущена чи ні.

Щоб зробити його ще чистішим, я пропоную перетворити послугу в синглтон з дуже дуже ледачим вилученням: тобто немає жодної інстанції у сінгтона екземплярах статичними методами. Статичний метод getInstance вашої служби / singleton просто повертає екземпляр синглтона, якщо він був створений. Але це насправді не запускає і не приводить сингл в сам. Служба запускається лише за допомогою звичайних методів запуску служби.

Тоді було б ще чистішим чином змінити схему дизайну сингл, щоб перейменовувати заплутаний метод 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 з обмеженнями, підкресленими Пітер-Яном Ван Робейсом.


32
Це хибно. onDestroy не гарантовано називається.
Пейс’єр

8
Коли в системі недостатньо пам’яті, ваша послуга буде автоматично вбита без виклику на ваш onDestroy, саме тому я кажу, що це є хибним.
Печер'є

17
@Pacerier, але якщо система вбиває процес, прапор екземпляра все одно буде скинутий. Я здогадуюсь, що при наступному завантаженні приймача (розміщення системи, що вбиває службу) статичний прапор "екземпляр" буде відтворений як нуль.
Том

2
Принаймні краще, ніж повторення через усі ті сервіси в isMyServiceRunning, які дійсно затримують речі, якщо робити це під час кожного обертання пристрою :)
Gunnar Forsgren - Mobimation

1
Ваша змінна інстанція не повинна бути оголошена остаточною, інакше вона не може бути встановлена ​​або нульова методами onCreate () або onDestroy ().
k2col

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, якщо вже існує служба. Якщо ні, нуль буде повернуто.

Див. Загальнодоступний реферат ComponentName startService (Служба намірів) .

Думаю, це не так, як перевірка, тому що вона запускає послугу, тому ви можете додати stopService(someIntent);під кодом.


11
Не зовсім те, що кажуть документи. За вашим посиланням: "Повертається, якщо служба запускається або вже працює, повертається ComponentName фактично запущеної послуги; в іншому випадку, якщо послуга не існує, нуль повертається."
Габріель

Гарне мислення ... але не підходить до поточної ситуації.
Code_Life

5
це не належним чином, тому що при запуску IDE if(startService(someIntent) != null)це перевірить, IsserviceRunningале це також відтворить нову службу.
Чінтан Хетія

Як зазначається, якщо ви припините послугу після цього контролю, це буде корисно для цієї проблеми. Але навіщо запускати та зупиняти послугу ні за що?
Танер

6
це запустить послугу, чи не так? Просто хочу перевірити стан сервісу, а не запускати його ...
Raptor

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 (Намір) , але якщо є якісь приймачі для наміру, ця функція буде заблокована та негайно відправити їх перед поверненням.

Подумайте про цей хак як про "пінг"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у Service.onCreate()і falseв , 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, коли послуга починається, і скасуйте її, коли послуга знищена. Здійснюючи свою діяльність (або будь-який компонент), надішліть службі локальну трансляцію, і якщо вона відповість, ви знаєте, що вона працює. Зверніть увагу на тонку різницю між 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. ( Тут обговорюється )

Послуги можуть працювати самостійно, прив'язуватися до діяльності або обох. Спосіб перевірити активність, чи працює Ваша Служба чи ні, - це створити інтерфейс (який розширює Binder), де ви заявляєте про методи, які розуміють і те, і Діяльність та Сервіс. Це можна зробити, створивши власний інтерфейс, де ви оголошуєте, наприклад, "isServiceRunning ()". Потім ви можете прив’язати свою активність до вашої служби, застосувати метод isServiceRunning (), служба перевірить, чи працює вона чи ні, і поверне булеві дані вашій діяльності.

Ви також можете використовувати цей метод, щоб зупинити Службу або взаємодіяти з нею іншим способом.

Я використовував цей підручник, щоб дізнатися, як реалізувати цей сценарій у своїй програмі.


3
Ця дискусія відбулася '12 / 26/07 '. Або це липень цього року (тобто в майбутньому), або ще до того, як Android був навіть загальнодоступним. Так чи інакше, це змушує мене не довіряти цьому.
Том

Це обговорення з 26 грудня 2007 року Вони обговорюють попередню версію я думаю ( developer.android.com/sdk/OLD_RELEASENOTES.html#m3-rc37a ) , який був випущено 14 грудня 2007 року
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 зі службою?
Дейв Нотаж

Де взяти контекст?
базилік

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

Єдина проблема з цим полягає в тому, якщо служба - це служба Sticky і вона перезапускається сама. Виклик до isServiceCreate () поверне помилкове після запуску послуги, оскільки mInstance буде недійсним.
Mira_Cole

1
Чи не буде onCreate викликатися тоді, коли служба перезапуститься?
TheRealChx101

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 ви можете додати boolean змінну в супровідний об'єкт і перевірити його значення з будь-якого класу, який ви бажаєте:

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, але в класі Котліна. Спасибі 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
Даніель Шац

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 порівняння як імена пакетів і імена класів. І на пристрої не може бути двох додатків з однаковою назвою пакета.

Метод рівних () 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

Це більше стосується налагодження намірної служби, оскільки вони породили нитку, але можуть працювати і для звичайних служб. Я знайшов цю тему завдяки Binging

У моєму випадку я пограв з налагоджувачем і виявив подання теми. Це виглядає як значок кулі в MS Word. У будь-якому випадку, вам не потрібно бути в режимі налагодження, щоб використовувати його. Натисніть на процес і натисніть на цю кнопку. Будь-які сервіси намірів з’являться під час роботи, принаймні, на емуляторі.


0

Якщо послуга належить до іншого процесу або APK, використовуйте рішення, засноване на ActivityManager.

Якщо у вас є доступ до його джерела, просто використовуйте рішення на основі статичного поля. Але замість використання булевого я б запропонував використовувати об'єкт Date. Поки служба працює, просто оновіть її значення на "зараз", а після завершення встановіть її на нуль. З цього виду можна перевірити, чи його нуль або дата занадто стара, це означає, що вона не працює.

Ви також можете надсилати сповіщення про трансляцію від своєї служби, вказуючи, що працює над додатковою інформацією, наприклад про хід.


0

Всередині TheServiceClass визначають:

 public static Boolean serviceRunning = false;

Тоді In onStartCommand (...)

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

    serviceRunning = true;
    ...
}

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

} 

Потім зателефонуйте if(TheServiceClass.serviceRunning == true)з будь-якого класу.


4
Це не працює, якщо Android вбиває службу.
Гейзенберг

@Heisenberg Я щойно це пережив. Ви знаєте, чому ні?
Тим

@Heisenberg, коли мою програму вбиває ОС, сервіс перезапускається і встановлює статичний bool в істинному стані, але після отримання цього повідомлення повідомляється помилковим
Тім,

це не спрацює, якщо ви телефонуєте stopService. Принаймні, для послуг Намір. onDestroy()буде викликаний негайно, але onHandleIntent()все ще працюватиме
serggl

1
@Heisenberg Не вбиває службу через низьку пам’ять - це також означає вбивство процесу?
андроїд розробник

0

просте використання зв'язується з не створюють автоматичне - див. 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.

Примітка. Цей метод призначений лише для налагодження або реалізації користувальницьких інтерфейсів типу управління послугами.


пс. Документація на андроїд вводить в оману. Я відкрив проблему з трекером Google, щоб усунути будь-які сумніви:

https://issuetracker.google.com/isissue/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 (Інтенційна служба, String разрешеноType, 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;
}

*


bindResult (повернене значення методу bindService) не стає помилковим, якщо служба не працює.
Shangeeth Sivan

0

Моє перетворення котліну на 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
Тільки щоб ніхто не оновлював цінність для вас, коли вони вбивають службу
Gunnar Forsgren - Mobimation

коли буде введено службу onDestroy (), спрацьовує і можливо оновити її стан
Jongz Puangput

5
@JongzPuangput, onDestroyне завжди викликається, коли служба вбита. Наприклад, я бачив, як мої служби загинули в ситуаціях з низькою пам’яттю, не onDestroyвикликаючи.
Сем

@Sam Тоді як називатимуться?
Ruchir Baronia

2
@RuchirBaronia Наскільки я пам’ятаю, ви просто не отримуєте повідомлення, коли ваші речі вбиті. Я вважаю, що Android призначений для того, щоб вбивати додатки за потреби, і програми повинні бути розроблені таким чином, щоб очікувати їх вбивства в будь-який момент без повідомлення.
Сем
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.