Jak sprawdzić, czy usługa działa na Androidzie?

Jak sprawdzić, czy usługa w tle (na Androida) działa?

Chcę mieć aktywność na Androidzie, która włącza stan usługi - pozwala mi ją włączyć, jeśli jest wyłączona i wyłączona, jeśli jest włączona.

Author: Peter Mortensen, 2009-03-01

23 answers

Miałem ten sam problem nie tak dawno temu. Ponieważ moja usługa była lokalna, skończyłem po prostu używając statycznego pola w klasie service do przełączania stanu, jak opisano w hackbod tutaj

Edycja (dla przypomnienia):

Oto rozwiązanie zaproponowane przez hackbod:

Jeśli Twój kod klienta i serwera jest częścią tego samego.apk i jesteś Wiązanie się z usługą z konkretnym zamiarem (takim, który określa dokładną klasę obsługi), wtedy można po prostu mieć Twój serwis zestaw a zmienna globalna, gdy jest uruchomiona, którą klient może sprawdzić.

Celowo nie mamy API, aby sprawdzić, czy usługa jest biegać, bo prawie bez przerwy, gdy chce się coś w ten sposób kończysz z warunkami rasy w swoim kodzie.

 249
Author: miracle2k,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-17 20:01:04

Używam następujących Z wewnątrz działania:

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

I nazywam to za pomocą:

isMyServiceRunning(MyService.class)

Działa to niezawodnie, ponieważ opiera się na informacjach o uruchomieniu usług dostarczanych przez system operacyjny Android za pośrednictwem ActivityManager#getRunningServices.

Wszystkie podejścia przy użyciu ondestroy lub onSometing zdarzeń lub Binderów lub zmiennych statycznych nie będzie działać niezawodnie, ponieważ jako deweloper nigdy nie wiadomo, kiedy Android zdecyduje się zabić proces lub który z wymienionych wywołań zwrotnych są wywoływane lub nie. Zwróć uwagę na kolumnę "killable" w tabeli zdarzeń cyklu życia w dokumentacji systemu Android.

 1542
Author: geekQ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-05 18:57:14

Mam!

Musisz

Zadzwonić, aby Twoja usługa została prawidłowo zarejestrowana, a przejście BIND_AUTO_CREATE nie wystarczy.

Intent bindIntent = new Intent(this,ServiceTask.class);
startService(bindIntent);
bindService(bindIntent,mConnection,0);

A teraz Klasa 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;
     }
}
 67
Author: Kevin Parker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-24 06:06:14

Małym dopełnieniem jest:

Moim celem jest wiedzieć, czy usługa działa bez uruchamiania go, jeśli nie działa.

Wywołanie bindService lub wywołanie intencji, która może zostać przechwycona przez usługę, nie jest dobrym pomysłem, ponieważ uruchomi usługę, jeśli nie jest uruchomiona.

Tak więc, jak zasugerował miracle2k, najlepiej jest mieć statyczne pole w klasie usług, aby wiedzieć, czy usługa została uruchomiona, czy nie.

Aby było jeszcze czystsze, proponuję przekształć usługę w singleton z bardzo leniwym pobieraniem: to znaczy, nie ma instancji w ogóle instancji singleton za pomocą metod statycznych. Statyczna metoda getInstance usługi / singleton po prostu zwraca instancję Singletona, jeśli została utworzona. Ale w rzeczywistości nie uruchamia ani nie uruchamia samego Singletona. Usługa jest uruchamiana tylko za pomocą normalnych metod uruchamiania usługi.

Wtedy byłoby jeszcze czystsze, aby zmodyfikować singleton wzorzec projektowy do zmiany nazwy mylącej metody getInstance na coś w rodzaju metody isInstanceCreated() : boolean.

Kod będzie wyglądał następująco:

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

To rozwiązanie jest eleganckie, ale ma znaczenie tylko wtedy, gdy masz dostęp do klasy usług i tylko dla klas jest dostępna aplikacja / pakiet usługi. Jeśli Twoje klasy znajdują się poza aplikacją/pakietem usług, możesz odpytywać ActivityManager z ograniczeniami podkreślonymi przez Pieter-Jan Van Robays.

 51
Author: Snicolas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-05 19:00:24

Możesz użyć tego (jeszcze tego nie próbowałem, ale mam nadzieję, że to zadziała):

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

Metoda startService zwraca obiekt ComponentName, jeśli istnieje już uruchomiona usługa. Jeśli nie, zostanie zwrócona wartość null.

Zobacz Public abstract ComponentName startService (Intent service).

To chyba nie jest tak jak sprawdzanie, bo uruchamia serwis, więc można dodać stopService(someIntent); pod kodem.

 22
Author: Keenan Gebze,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-05 18:54:29
    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
Author: J.R,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-10 05:20:13

Nieco zmodyfikowałem jedno z powyższych rozwiązań, ale przekazując klasę zamiast ogólnej nazwy łańcucha znaków, aby mieć pewność porównania łańcuchów pochodzących z tej samej metody 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;
    }
}

A następnie

Boolean isServiceRunning = ServiceTools.isServiceRunning(
                    MainActivity.this.getApplicationContext(),
                    BackgroundIntentService.class);
 11
Author: loretoparisi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-13 14:26:04

Chcę tylko dodać notkę do odpowiedzi przez @Snicolas. Następujące kroki mogą być użyte do sprawdzenia usługi stop z / bez wywołania onDestroy().

  1. onDestroy() wywołane: przejdź do Ustawienia - > Aplikacja - > uruchomione usługi - > Wybierz i zatrzymaj usługę.

  2. onDestroy() Nie wywołane: przejdź do Ustawienia - > Aplikacja - > Zarządzaj aplikacjami - > Wybierz i "Wymuś zatrzymanie" aplikacji, w której działa usługa. Jednak, jak aplikacja jest zatrzymany tutaj, więc na pewno instancje usług również zostaną zatrzymane.

Na koniec chciałbym wspomnieć, że wspomniane tam podejście wykorzystujące zmienną statyczną w klasie singleton działa dla mnie.

 7
Author: Paul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-22 00:22:39

onDestroy nie zawsze jest nazywany w serwisie, więc to jest bezużyteczne!

Na przykład: po prostu uruchom aplikację ponownie z jedną zmianą z Eclipse. Aplikacja jest definitywnie wyłączana przy użyciu SIG: 9.

 6
Author: Kevin Parker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-02 11:06:07

To jest wyciąg z Android docs

Uporządkowane transmisje (wysłane z kontekstem .sendOrderedBroadcast ) są dostarczane do jednego odbiorcy na raz. Jak każdy odbiornik wykonuje w turn, może propagować wynik do następnego odbiornika, lub może całkowicie przerwij transmisję, aby nie została przekazana innym odbiorniki.

pomyśl o tym hacku jako o" pingowaniu"Service ponieważ możemy nadawać synchronicznie możemy nadawać i uzyskać wynik synchronicznie na wątku UI.

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;   
        }
    }
 6
Author: peter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-14 07:57:42

Przede wszystkim nie można próbować dotrzeć do usługi za pomocą Menedżera ActivityManager. (Omówione tutaj )

Usługi mogą działać samodzielnie, być związane z działaniem lub obiema. Sposobem sprawdzenia aktywności, czy usługa jest uruchomiona, jest utworzenie interfejsu (który rozszerza Binder), w którym deklaruje się metody, które rozumieją zarówno aktywność, jak i usługa. Możesz to zrobić poprzez stworzenie własnego interfejsu, w którym zadeklarujesz na przykład " isServiceRunning ()". Następnie możesz związać Twoja aktywność w usłudze, Uruchom metodę isServiceRunning (), usługa sama sprawdzi, czy jest uruchomiona, czy nie i zwróci wartość logiczną do Twojej aktywności.

Możesz również użyć tej metody, aby zatrzymać usługę lub współdziałać z nią w inny sposób.

Użyłem tego tutoriala , aby dowiedzieć się, jak zaimplementować ten scenariusz w mojej aplikacji.

 5
Author: Pieter-Jan Van Robays,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-06 17:07:28

Aby sprawdzić, czy usługa jest uruchomiona, wystarczy ją zapytać. Zaimplementuj BroadcastReceiver w swojej usłudze, która odpowiada na pingi z twoich działań. Zarejestruj BroadcastReceiver po uruchomieniu usługi i Wyrejestruj go, gdy usługa zostanie zniszczona. Z Twojej aktywności (lub dowolnego komponentu), Wyślij lokalną transmisję do serwisu i jeśli odpowie, wiesz, że działa. Zwróć uwagę na subtelną różnicę między ACTION_PING i ACTION_PONG w kodzie poniżej.

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;
            }
        }
    };
}
 5
Author: Ben H,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-29 21:12:06

Xamarin C# version:

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;
}
 5
Author: Nima,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-04 08:50:01

W przypadku użycia podanym tutaj możemy po prostu użyć wartości zwracanej przez metodę stopService(). Zwraca true jeśli istnieje określona usługa i zostanie ona zabita. Else zwraca false. Możesz więc ponownie uruchomić usługę, jeśli wynikiem jest false, w przeciwnym razie jest pewne, że bieżąca usługa została zatrzymana. :) Byłoby lepiej, gdybyś spojrzał na to.

 4
Author: Rahul Raveendran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-28 09:55:23

Ponownie, inna alternatywa, że ludzie mogą znaleźć czystsze, jeśli używają intencji oczekujących (na przykład z 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);
}

Gdzie {[2] } jest stałą, którą definiujesz prywatnie w swojej klasie, aby zidentyfikować oczekujące intencje związane z Twoją usługą.

 4
Author: Snicolas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-06 23:41:37

Poniżej znajduje się elegancki hack, który obejmuje wszystkie Ifs. Dotyczy to wyłącznie usług lokalnych.

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

A później:

    if(AService.isServiceCreated()){
        ...
    }else{
        startService(...);
    }
 2
Author: TheRealChx101,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-19 14:08:18

Może być kilka usług o tej samej nazwie klasy.

Właśnie stworzyłem dwie aplikacje. Nazwa pakietu pierwszej aplikacji to com.example.mock. Stworzyłem w aplikacji podpakiet o nazwie lorem oraz usługę o nazwie Mock2Service. Tak więc jego pełna nazwa to com.example.mock.lorem.Mock2Service.

Następnie stworzyłem drugą aplikację i usługę o nazwie Mock2Service. Nazwa pakietu drugiej aplikacji to com.example.mock.lorem. W pełni kwalifikowana nazwa usługi to com.example.mock.lorem.Mock2Service.

Oto moje wyjście 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

A lepszym pomysłem jest porównanie instancji ComponentName, Ponieważ equals() z ComponentName porównuje zarówno nazwy pakietów, jak i nazwy klas. Na urządzeniu nie mogą być zainstalowane dwie aplikacje o tej samej nazwie pakietu.

Metoda equals() z 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

 1
Author: Maksim Dmitriev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-27 08:35:23

Odpowiedź geekQ ale w klasie Kotlin. Dzięki 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
}

The call

isMyServiceRunning(NewService::class.java)
 1
Author: Luis Eduardo Moreno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-23 21:43:10

Odnosi się to bardziej do debugowania usług Intentowych, ponieważ odradzają one wątek, ale mogą działać również dla zwykłych usług. Znalazłem ten wątek dzięki Binging

W moim przypadku pobawiłem się debugerem i znalazłem Widok wątku. Wygląda jak ikona punktora w MS Word. Tak czy inaczej, nie musisz być w trybie debuggera, aby go używać. Kliknij na proces i kliknij ten przycisk. Wszelkie usługi intencyjne pojawią się podczas ich działania, przynajmniej na emulator.

 0
Author: Joe Plante,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-03 20:38:00

Jeśli usługa należy do innego procesu lub APK, użyj rozwiązania opartego na Menedżerze ActivityManager.

Jeśli masz dostęp do jego źródła, po prostu użyj rozwiązania opartego na polu statycznym. Ale zamiast tego używając logiki sugerowałbym użycie obiektu Date. Gdy usługa jest uruchomiona, po prostu zaktualizuj jej wartość do ' now ' i po jej zakończeniu ustaw ją na null. Z aktywności możesz sprawdzić, czy jej null lub data jest za stara, co oznacza, że nie jest uruchomiona.

Możesz również wysłać powiadomienie o transmisji z usługi wskazujące, że działa wzdłuż dalszych informacji, takich jak postęp.

 0
Author: FranMowinckel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-04 11:14:41

Inside TheServiceClass define:

 public static Boolean serviceRunning = false;

Następnie w onStartCommand(...)

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

    serviceRunning = true;
    ...
}

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

} 

Następnie wywołaj if(TheServiceClass.serviceRunning == true) z dowolnej klasy.

 0
Author: fullMoon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-23 18:35:09

proste użycie bind z don ' t create auto - zobacz ps. i aktualizacja...

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

Przykład:

    Intent bindIntent = new Intent(context, Class<Service>);
    boolean bindResult = context.bindService(bindIntent, ServiceConnection, 0);

Dlaczego nie używać? getRunningServices()

List<ActivityManager.RunningServiceInfo> getRunningServices (int maxNum)
Return a list of the services that are currently running.

Uwaga: ta metoda jest przeznaczona tylko do debugowania lub implementacji interfejsów użytkownika typu service management.


Ps. dokumentacja Androida wprowadza w błąd otworzyłem problem w Google tracker, aby wyeliminować wszelkie wątpliwości:

Https://issuetracker.google.com/issues/68908332

Jak widzimy usługa bind faktycznie wywołuje transakcję poprzez binder activitymanager poprzez segregatory pamięci podręcznej usługi - i dint śledzić, która usługa jest odpowiedzialna za Wiązanie, ale jak widzimy wynik dla bind jest:

int res = ActivityManagerNative.getDefault().bindService(...);
return res != 0;

Transakcja odbywa się za pośrednictwem Bindera:

ServiceManager.getService("activity");

Następny:

  public static IBinder getService(String name) {
    try {
        IBinder service = sCache.get(name);
        if (service != null) {
            return service;
        } else {
            return getIServiceManager().getService(name);

Jest to ustawione w ActivityThread poprzez:

 public final void bindApplication(...) {

        if (services != null) {
            // Setup the service cache in the ServiceManager
            ServiceManager.initServiceCache(services);
        }

To się nazywa ActivityManagerService in method:

 private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
    ...
    thread.bindApplication(... , getCommonServicesLocked(),...)

Potem:

 private HashMap<String, IBinder> getCommonServicesLocked() {

Ale nie ma "aktywności" Tylko pakiet okien i alarm..

Więc musimy wrócić do połączenia:

 return getIServiceManager().getService(name);

    sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());

To sprawia, że połączenie przez:

    mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);

Co prowadzi do:

BinderInternal.getContextObject()

I jest to metoda natywna....

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

Nie mam teraz czasu na kopanie w c, więc dopóki nie wybiorę rest call, zawieszę odpowiedź.

Ale najlepszym sposobem sprawdzenia czy usługa działa jest create bind (jeśli bind nie jest utworzony usługa nie istnieje) - i zapytanie usługi o jego stan za pomocą bind (używając przechowywanego wewnętrznego znacznika na nim stan).

Aktualizacja 23.06.2018

Znalazłem te interesujące:

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

W skrócie:)

"dostarczyć segregator do już związanej usługi. Ta metoda jest synchroniczna i nie uruchomi usługi docelowej, jeśli nie jest obecna."

Public ibinder peekService(Intent service, String resolvedType, String callingPackage) throws 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;
}

*

 0
Author: ceph3us,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-23 16:05:03

Spokojnie, chłopaki... :)

Myślę, że najbardziej odpowiednim rozwiązaniem jest trzymanie pary klucz-wartość w SharedPreferences o tym, czy usługa jest uruchomiona, czy nie.

Logika jest bardzo prosta; w dowolnej pozycji w klasie usług; umieść wartość logiczną, która będzie działać jako Flaga dla Ciebie o tym, czy usługa jest uruchomiona, czy nie. Następnie odczytaj tę wartość gdziekolwiek chcesz w swojej aplikacji.

Przykładowy kod, którego używam w mojej aplikacji znajduje się poniżej:

In my Service class (A service dla strumienia Audio), wykonuję następujący kod, gdy usługa jest włączona;

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

Następnie w dowolnej aktywności mojej aplikacji sprawdzam status usługi za pomocą następującego kodu;

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

Brak specjalnych uprawnień, brak pętli... Łatwy sposób, czyste rozwiązanie:)

Jeśli potrzebujesz dodatkowych informacji, zapoznaj się z link

Mam nadzieję, że to pomoże.
 -3
Author: Taner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-04 10:21:27