Как проверить, если сервис работает на Android?

голоса
774

Как я могу проверить, если фоновая служба (на Android) работает?

Я хочу Android деятельности, которая переключает состояние службы - это позволяет мне включить его, если он выключен и выключается, если он включен.

Задан 01/03/2009 в 19:09
источник пользователем
На других языках...                            


24 ответов

голоса
1k

Я использую следующий внутри деятельности:

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 события или Биндер или статические переменные не будет работать надежно , потому что как разработчик вы никогда не знаете, когда Android решает убить процесс или какая из указанных обратных вызовов называются или нет. Пожалуйста , обратите внимание на «Killable» столбец в таблице событий жизненного цикла в документации Android.

Ответил 07/05/2011 d 13:54
источник пользователем

голоса
244

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

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

Вот решение, предложенное hackbod:

Если ваш клиент и коды сервера является частью того же .apk и вы являетесь обязательными для службы с конкретным Intent (тот, который определяет точный класс обслуживания), то вы можете просто иметь свой сервис установить глобальную переменный, когда она работает, что ваш клиент может проверить.

Мы намеренно не имеют API, чтобы проверить, является ли служба работает, потому что, почти без сбоев, когда вы хотите сделать что-то подобное, что вы в конечном итоге с условиями гонки в вашем коде.

Ответил 03/03/2009 d 23:58
источник пользователем

голоса
67

Понял!

Вы должны позвонить 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;
     }
}
Ответил 12/02/2011 d 05:42
источник пользователем

голоса
50

Небольшое дополнение является:

Моя цель состоит в том, чтобы узнать погоду служба работает без actualy работает, если она не работает.

Вызов bindService или вызова намерение, которое может быть перехвачено службой не является хорошей идеей, то как это будет запустить службу, если она не работает.

Так что, как miracle2k предложил, лучше всего иметь статическое поле в классе обслуживания, чтобы узнать, работает ли служба или нет.

Для того, чтобы сделать его еще чист, я предлагаю , чтобы преобразовать службу в одноточечного с очень очень ленивой выборкой: то есть, нет конкретизации на всех одноплодных например , через статические методы. Статический метод деЫпзЬапсе вашего сервиса / одноточечного просто возвращает экземпляр синглтона , если оно было создано. Но это не actualy начала или само создание экземпляра одиночки. Служба запускается только через обычные методы запуска службы.

Тогда было бы еще чище изменить одноплодный шаблон проектирования переименовывать запутанный метод 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 с ограничениями подчеркнутых Pieter-Jan Van Robays.

Ответил 20/05/2011 d 11:58
источник пользователем

голоса
22

Вы можете использовать это (я не пробовал это, но я надеюсь, что это работает):

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);под кодом.

Ответил 23/09/2010 d 18:01
источник пользователем

голоса
13
    public boolean checkServiceRunning(){
         ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
        for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) 
                {
                    if ("com.example.yourpackagename.YourServiceName"
                            .equals(service.service.getClassName())) 
                    {
                        return true;
                    }
                }
             return false;
    }
Ответил 14/07/2014 d 04:23
источник пользователем

голоса
10

Я слегка модифицировал один из решений, представленных выше, но проходя класс вместо родового имени строки, для того, чтобы быть уверенными, чтобы сравнить строки выходят из той же методы 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);
Ответил 13/07/2016 d 14:26
источник пользователем

голоса
7

Я просто хочу , чтобы добавить примечание к ответу по @Snicolas. Следующие шаги могут быть использованы для проверки остановки службы с / без вызова onDestroy().

  1. onDestroy() называется: Перейдите в раздел Настройки -> приложения -> Running Services -> Выбрать и остановить службу.

  2. onDestroy()не Вызывается: Перейдите в раздел Настройки -> приложения -> Управление приложениями -> Выбрать и «Force Стоп» приложение, в котором ваша служба работает. Однако, как ваше приложение здесь остановлено, так определенно экземпляры службы также будут остановлены.

Наконец, я хотел бы отметить, что подход, упомянутые там с помощью статической переменной в одиночки классе работает для меня.

Ответил 16/09/2012 d 17:54
источник пользователем

голоса
6

onDestroy не всегда вызывается в службе, так что это бесполезно!

Например: Просто запустите приложение снова с одним изменением от Eclipse. Приложение принудительно вышел с помощью Sig: 9.

Ответил 12/02/2011 d 05:26
источник пользователем

голоса
5

Правильный способ проверить , если служба запущена, чтобы просто спросить его. Реализовать 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;
            }
        }
    };
}
Ответил 29/10/2016 d 20:15
источник пользователем

голоса
5

Это выдержка из Android Docs

Заказанный трансляций (отправленный с Context.sendOrderedBroadcast ) доставляется на один приемник одновременно. Поскольку каждый приемник выполняет , в свою очередь, он может распространяться результат к следующему приемнику, или он может полностью прервать передачу , так что он не будет передан другим получателям.

Это немного рубить , но думать об этом как «пингом»Service , так как мы можем транслировать syncronously мы можем транслировать и получить результат синхронно в потоке пользовательского интерфейса.

Service

BroadcastReceiver ,

@Override
public void onCreate() {
   LocalBroadcastManager
     .getInstance(this)
     .registerReceiver(new ServiceEchoReceiver(), IntentFilter("echo");
}

private class ServiceEchoReceiver{
    public void onReceive (Context context, Intent intent) {
      LocalBroadcastManager
         .getInstance(this)
         .sendBroadcastSync(new Intent("echo"));
    }
}

Activity

    bool serviceRunning = false;

    protected void onCreate (Bundle savedInstanceState){
        LocalBroadcastManager.getInstance(this).registerReceiver(echo);
        LocalBroadcastManager.getInstance(this).sendBroadcastSync(new Intent("echo"));
        if(!serviceRunning){
           //try and run the service
        }
    }

    private BroadcastReceiver echo = new BroadcastReceiver(){
        public void onReceive (Context context, Intent intent) {
          serviceRunning = true;   
        }
    }
Ответил 19/09/2016 d 17:48
источник пользователем

голоса
5

Прежде всего вы musn't попытаться достичь обслуживания с помощью ActivityManager. (Обсуждаемые здесь )

Услуги могут работать сама по себе, быть привязаны к деятельности или оба. Способ проверить в деятельности, если ваша служба работает или нет, сделав интерфейс (который расширяет Binder), где Вы заявляете методы, как активность и служба, понять. Вы можете сделать это, сделав свой собственный интерфейс, где вы объявляете, например «isServiceRunning ()». Затем вы можете связать вашу деятельность с вашей службой, запустите метод isServiceRunning (), служба будет проверять себя, если он работает или нет, и возвращает логическое значение для вашей деятельности.

Вы также можете использовать этот метод, чтобы остановить службу или взаимодействовать с ним по-другому.

Я использовал этот учебник , чтобы узнать , как реализовать этот сценарий в моем приложении.

Ответил 30/03/2011 d 15:56
источник пользователем

голоса
4

Xamarin C # verison.

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;
        }
Ответил 13/06/2016 d 19:00
источник пользователем

голоса
4

Опять же , еще одна альтернатива , что люди могли бы найти чисты , если они используют ожидающие намерения (например , с 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это константа , что вы определяете в частном порядке в вашем классе , чтобы определить , ожидающие намерения , связанные с вашими услугами.

Ответил 07/08/2014 d 00:41
источник пользователем

голоса
4

Для потребительного случае приведенного здесь мы можем просто использовать в stopService()возвращаемом значении методы. Возвращает , trueесли существует указанную службу , и его убивают. Иначе он возвращается false. Таким образом , вы можете перезапустить службу , если результат falseеще уверен , что в настоящее время служба была остановлена. :) Было бы лучше , если вы посмотрите на это .

Ответил 28/05/2013 d 10:55
источник пользователем

голоса
1

Реакция 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)
Ответил 23/03/2018 d 21:43
источник пользователем

голоса
1

Ниже элегантный Хак , который охватывает все 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(...);
    }
Ответил 19/01/2018 d 14:08
источник пользователем

голоса
1

Внутри 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)из любого класса.

Ответил 23/10/2015 d 18:35
источник пользователем

голоса
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;
}

ComponentName

Ответил 27/03/2014 d 09:11
источник пользователем

голоса
0

простое использование связывают с не создавать авто - см пс.

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/issues/68908332

как мы можем видеть привязки службы на самом деле вызывает транзакцию через ActivityManager вяжущего через вяжущий кэш Service - я вмятина дорожки, служба отвечает за связывание, но, как мы можем видеть результат для связывания является:

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

У меня нет времени сейчас, чтобы копаться в с так пока я не проанализируем вызов остальное я приостановить мой ответ.

но лучший способ для проверки , если служба запущена , чтобы создать привязку (если привязка не создана служба не существует) - и запросить службу о своем состоянии через привязку (используя сохраненный внутренний флаг на нем состояние).

Ответил 11/03/2017 d 17:11
источник пользователем

голоса
0
public static boolean isServiceRunning;

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
isServiceRunning = true;
return START_NOT_STICKY;
}

@Override
    public void onDestroy() {
        super.onDestroy();
        isServiceRunning = false;
    }

ИЛИ

если не хочет использовать статический, то пользователь SharedPreferences

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    PrefManager.getPref().saveBoolean(AppConstants.Pref.IS_SERVICE_RUNNING, true);
    return START_NOT_STICKY;
}

@Override
public void onDestroy() {
    super.onDestroy();
    PrefManager.getPref().saveBoolean(AppConstants.Pref.IS_SERVICE_RUNNING, false);
}

PrefManager мой синглтон класс для управления всеми предпочтениями.

Ответил 19/01/2017 d 12:33
источник пользователем

голоса
0

Если услуга относится к другому процессу или APK использовать решение, основанное на ActivityManager.

Если у вас есть доступ к своему источнику, просто использовать решение, основанное на статическом поле. Но вместо того, чтобы с помощью булева я предложил бы использовать объект Date. Несмотря на то, что служба работает, просто обновить его значение «сейчас» и когда она заканчивает установить его в нуль. От деятельности вы можете проверить, если его пустым или дата слишком стар, что будет означать, что она не работает.

Вы также можете отправить уведомление широковещательного от службы о том, что бежит по дальнейшей информации, как прогресс.

Ответил 04/08/2013 d 12:14
источник пользователем

голоса
0

Это относится больше к отладке Намерения службы, поскольку они порождают поток, но может работать для обычных услуг, а также. Я нашел эту тему благодаря перееданию

В моем случае, я играл с отладчиком и нашел вид резьбы. Это вид выглядит как значок точки пули в MS Word. В любом случае, вы не должны находиться в режиме отладчика, чтобы использовать его. Нажмите на процесс и нажмите на эту кнопку. Любое Намерение услуги будет отображаться в то время как они работают, по крайней мере, на эмуляторе.

Ответил 03/08/2012 d 21:32
источник пользователем

голоса
-3

Успокойтесь, ребята ... :)

Я думаю , что наиболее подходящим решением является проведение пары ключ-значение в 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);
}

Никаких специальных разрешений, без петель ... Простой способ, чистое решение :)

Если вам нужна дополнительная информация, пожалуйста , обратитесь к ссылке

Надеюсь это поможет.

Ответил 02/07/2013 d 21:46
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more