Android'de bir hizmetin çalışıp çalışmadığını nasıl kontrol edebilirim?


936

Bir arka plan hizmetinin çalışıp çalışmadığını nasıl kontrol ederim?

Hizmetin durumunu değiştiren bir Android etkinliği istiyorum - açıksa kapatıp açmamı sağlar.



17
doğru cevap aşağıdadır ve işaretli değil: stackoverflow.com/a/5921190/2369122
toidiu

1
@toidiu Bu daha önce böyle bir şey yapmadıysa getRunningTasks(), muhtemelen öyle olacaktır.
Kevin Krumwiede

getSystemService () işlevini kullanarak çalışan tüm hizmetleri alabilirsiniz. döngü ve hizmet burada listeden var kontrol küçük bir örnek görebilirsiniz wiki.workassis.com/android-check-the-service-is-running
Bikesh M

Yanıtlar:


292

Uzun zaman önce aynı problemi yaşadım. Hizmetim yerel olduğundan, burada hackbod tarafından açıklandığı gibi, durumu değiştirmek için hizmet sınıfında statik bir alan kullandım

EDIT (kayıt için):

Hackbod tarafından önerilen çözüm:

İstemciniz ve sunucu kodunuz aynı .apk dosyasının bir parçasıysa ve hizmete somut bir Niyet (tam hizmet sınıfını belirten bir tane) ile bağlanıyorsanız, hizmetinizi çalıştırırken bir genel değişken ayarlamanız yeterlidir. müşteriniz kontrol edebilir.

Kasten bir hizmetin çalışıp çalışmadığını kontrol etmek için bir API'miz yok, çünkü neredeyse başarısız olmadan, kodunuzda yarış koşullarına sahip olduğunuz gibi bir şey yapmak istediğinizde.


27
@Pacerier, başvuruda bulunduğunuz çözüm hizmetin başlatılmasını gerektirir ve bence en iyi esnek çözüm, bir hizmetin başlatılmadan çalışıp çalışmadığını kontrol etmenize izin vermelidir.
Tom

17
Hizmet sistem tarafından durdurulursa, bunu nasıl tespit edersiniz ve değişkeninizi değiştirirsiniz?
jmng

23
Uygulama öldürüldüğünde, başlattığı hizmet de öldürülür ancak hizmetin onDestroy()çağrısı yapılmaz. Dolayısıyla statik değişken, böyle bir senaryoda güncellenemez ve bu da tutarsız davranışlara neden olur.
faizal

5
@faizal Statik değişken de yeniden başlatılmaz, böylece hizmetin artık çalışmadığını gösteren varsayılan değere döndürülür mü?
PabloC

12
@faizal, yerel Hizmet ayrı bir işlem değildir, bu nedenle hizmet öldürülürse uygulama da öldürür.
Sever

1674

Bir faaliyetin içinden aşağıdakileri kullanıyorum:

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

Ve ben şunu kullanarak diyorum:

isMyServiceRunning(MyService.class)

ActivityManager # getRunningServices aracılığıyla Android işletim sistemi tarafından sağlanan hizmetlerin çalıştırılması hakkındaki bilgilere dayandığı için bu güvenilir bir şekilde çalışır .

OnDestroy veya onSometing olaylarını veya Bağlayıcıları veya statik değişkenleri kullanan tüm yaklaşımlar güvenilir bir şekilde çalışmaz, çünkü asla tanımadığınız bir geliştirici olarak, Android işleminizi öldürmeye karar verdiğinde veya belirtilen geri aramalardan hangisi çağrılır veya çağrılmaz. Android dokümanındaki yaşam döngüsü etkinlikleri tablosundaki "killable" sütununa dikkat edin .


85
Bu çözüm için teşekkürler. Eklemek istiyorum: Bunun yerine "com.example.MyService" MyService.class.getName ()
peter.bartos'u

10
Şahsen, statik bir alan kullanmaya gittim. GetRunningServices () kullanmak daha sağlam bir çözüm olmasına rağmen, bu iki çözümde sağlamlık ve verimlilik / basitlik arasında bir denge olduğuna inanıyorum. Bir hizmetin çalışıp çalışmadığını sık sık kontrol etmeniz gerekiyorsa, potansiyel olarak 30'dan fazla çalışan hizmet arasında döngü yapmak pek ideal değildir. Sistem tarafından yok edilen nadir bir servis durumu, bir try / catch bloğu veya START_STICKY kullanılarak ele alınabilir.
robguinness

80
Hayır, bu doğru bir yanıt değildir çünkü dokümanlarda da yazılmıştır: "Not: bu yöntem yalnızca hizmet yönetimi türü kullanıcı arayüzlerinde hata ayıklama veya uygulama amaçlıdır." Kontrol akışı için değil!
seb

40
İnsanlar bir sunucunun çalışıp çalışmadığını kontrol etmek için her şeyi yapmak zorunda zarif?
Rui Marques

80
Başlangıç Android O , getRunningServiceskullanımdan kaldırılmıştır. Bu yanıtın daha yeni bir sürüm için güncellenmesi gerekiyor.
Poring91

75

Anladım!

Sen GEREKİR çağrı startService()servis düzgün kayıtlı olması ve geçen için BIND_AUTO_CREATEyeterli olmayacaktır.

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

Ve şimdi ServiceTools sınıfı:

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

Bu sadece sistem hizmetlerini listeleyecektir, değil mi ?! Bu yüzden yerel servisim listeden çıkarıldı ve yanlış olacağım; (
Ewoks

Bu harici hizmetler ile çalışır, çünkü yerel hizmetler çalışıyorsanız oldukça açıktır.
Kevin Parker

11
Üzgünüm ama bunun süper aptalca cevap olduğunu söylemeliyim ... Neden süper açık ?!
Ewoks

10
Burada ne demek istediğini belli değil ... Kim çökmekten bahsediyordu ?! Onu çökertmede ilginç değilim. Hizmet başlatılabilir, durdurulabilir, belki de niyet hizmetiydi ve bittiğinde kendi başına duracaktır ... Soru, örneğin 3 dakika sonra hala çalışıp çalışmadığını nasıl anlayacağınızdır.
Ewoks

1
Bağlı bir hizmetin de başlatılması gerektiği izlenimini vermek yanlıştır. HAYIR. Bind auto create tam olarak ne diyorsa onu yapar. Hizmet henüz çalışmıyorsa hizmeti oluşturur (ve dolayısıyla "başlatır").
Sreedevi J

57

Küçük bir tamamlayıcı:

Amacım, bir hizmetin çalışmadığı halde gerçekte çalışmadan çalışıp çalışmadığını bilmek.

BindService'i çağırmak veya hizmet tarafından yakalanabilecek bir amacı aramak iyi bir fikir değildir, çünkü çalışmazsa hizmeti başlatacaktır.

Bu nedenle, miracle2k'nin önerdiği gibi, en iyisi, hizmetin başlatılıp başlatılmadığını bilmek için hizmet sınıfında statik bir alana sahip olmaktır.

Daha da temiz hale getirmek için, hizmeti çok tembel bir getirme ile tek birtonda dönüştürmeyi öneririm: yani, tekil örnekte statik yöntemlerle hiçbir somutlaşma yoktur . Hizmetinizin / singletonunuzun statik getInstance yöntemi, oluşturulmuşsa singleton örneğini döndürür. Fakat aslında singletonun kendisini başlatmaz veya başlatmaz. Hizmet yalnızca normal hizmet başlatma yöntemleri ile başlatılır.

Daha sonra, karmaşık getInstance yöntemini yöntem gibi bir şeye yeniden adlandırmak için singleton tasarım desenini değiştirmek daha da temiz olacaktır isInstanceCreated() : boolean.

Kod şöyle görünecektir:

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

Bu çözüm zariftir, ancak yalnızca hizmet sınıfına erişiminiz varsa ve yalnızca sınıflar için hizmetin uygulaması / paketi söz konusuysa geçerlidir. Sınıflarınız hizmet uygulamasının / paketinin dışındaysa, Pieter-Jan Van Robays tarafından vurgulanan sınırlamalarla ActivityManager'ı sorgulayabilirsiniz.


32
Bu kusurlu. onDestroy'un aranacağı garanti edilmez.
Pacerier

8
Sistemin belleği az olduğunda, hizmetiniz onDestroy'unuzu aramadan otomatik olarak öldürülecektir, bu yüzden bunun kusurlu olduğunu söylüyorum.
Pacerier

17
@Pacerier, ancak sistem işlemi öldürürse, örnek bayrağı yine de sıfırlanır. Ben alıcı bir sonraki yüklendiğinde (servis hizmeti öldürme sonrası) statik bayrak 'örnek' boş olarak yeniden olacağını tahmin ediyorum.
Tom

2
En azından her cihaz rotasyonunda yapılırsa işleri gerçekten geciktiren isMyServiceRunning'taki tüm bu hizmetler üzerinden yinelemekten daha iyi :)
Gunnar Forsgren - Mobimation 30:13

1
Örnek değişkeniniz son olarak bildirilmemelidir, aksi takdirde onCreate () veya onDestroy () yöntemleri tarafından ayarlanamaz veya boş bırakılamaz.
k2col

27

Bunu kullanabilirsiniz (henüz denemedim, ama umarım bu işe yarar):

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

Zaten çalışan bir hizmet varsa startService yöntemi bir ComponentName nesnesi döndürür. Değilse, null değeri döndürülür.

Genel özet BileşenAdı startService (Amaç hizmeti) konusuna bakın .

Bu sanırım kontrol gibi değil, çünkü hizmet başlıyor, böylece stopService(someIntent);kodun altına ekleyebilirsiniz .


11
Belgelerin tam olarak söylediği gibi değil. Bağlantınıza göre: "İade Hizmet başlatılırsa veya zaten çalışıyorsa, başlatılan gerçek hizmetin BileşenAdı döndürülür; aksi takdirde hizmet yoksa boş değer döndürülür."
Gabriel

Güzel düşünmek ... ama mevcut duruma uymuyor.
Code_Life

5
onun doğru yolu değil, çünkü IDE tetiklediğinde if(startService(someIntent) != null)bunu kontrol edecek IsserviceRunningama aynı zamanda yeni bir servis oynayacak.
Chintan Khetiya

Belirtildiği gibi, bu kontrolden sonra hizmeti durdurursanız, bu sorun için kullanışlı olacaktır. Peki, bir hizmeti neden boşuna başlatmalı ve durdurmalı?
Taner

6
bu hizmeti başlatacak, değil mi? Sadece servis durumunu başlatmak yerine kontrol etmek istiyorum ...
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 dokümanlarından bir alıntı :

Gibi (Niyet) sendBroadcast , ama orada bu işlev engeller Niyet herhangi alıcıları ve hemen dönmeden önce sürükleyiveririz eğer.

Bu kesmek "ping" olarak düşününService . Eşzamanlı olarak yayınlayabildiğimiz için, UI iş parçacığında eşzamanlı olarak yayın yapabilir ve bir sonuç elde edebiliriz .

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

Birçok uygulamada kazanan, tabii ki, ayarlandığında hizmet üzerinde statik boole alandır trueiçinde Service.onCreate()ve falsede Service.onDestroy()bu çok daha basit olduğu için.


Bu, kabul edilen çözümden çok daha iyi bir çözümdür, çünkü küresel değişken yöntemi hala hizmetin artık çalışmadığında çalıştığını göstereceğinden, Android hizmeti öldürürse başarısız olur. Bu senkron ping-pong yayın hile aslında bir hizmetin hayatta olup olmadığını kontrol etmek için SADECE güvenilir bir yöntemdir. Tek başına, eğer varsa, hizmeti SORMAYI sağlar. Yanıt verirse, hizmet canlı ve çalışır durumdadır, değilse başlatılmamış veya kapatılmışsa, program aracılığıyla veya sistem tarafından belleği kurtarmak için.
PhoenixRevealed

13

Yukarıda sunulan çözümlerden birini biraz değiştirdim, ancak aynı yöntemden çıkan dizeleri karşılaştırmak için genel bir dize adı yerine sınıfı geçirerek 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;
    }
}

ve sonra

Boolean isServiceRunning = ServiceTools.isServiceRunning(
                    MainActivity.this.getApplicationContext(),
                    BackgroundIntentService.class);

daha sıkı olmak için sınıf parametresini değiştirebilirsinizClass<? extends Service>
silentsudo

11

Bir hizmetin çalışıp çalışmadığını kontrol etmenin uygun yolu, bunu sormaktır. Hizmetinizde faaliyetlerinizdeki ping'lere yanıt veren bir BroadcastReceiver uygulayın. Hizmet başladığında BroadcastReceiver'ı kaydedin ve hizmet imha edildiğinde kaydını silin. Etkinliğinizden (veya herhangi bir bileşenden) hizmete yerel bir yayın amacı gönderin ve yanıt verirse çalıştığını bilirsiniz. Aşağıdaki kodda ACTION_PING ve ACTION_PONG arasındaki küçük farkı not edin.

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
Aslında bu yaklaşımı seviyorum. Biraz ağır bir kod akıllıca ama her zaman işe yarayacak. Yakında hiçbir zaman yayın amaçlarının kullanımdan kaldırıldığını görmüyorum :)
ShellDude

8

Sadece @Snicolas'ın cevabına bir not eklemek istiyorum. Durdurma servisini çağrılarak / çağırmadan kontrol etmek için aşağıdaki adımlar kullanılabilir onDestroy().

  1. onDestroy() çağrılan: Ayarlar -> Uygulama -> Çalışan Hizmetler -> Hizmetinizi seçin ve durdurun.

  2. onDestroy()Aranmadı: Servisinizin çalıştığı uygulamanızı Ayarlar -> Uygulama -> Uygulamaları Yönet -> seçin ve "Zorla Durdur" a gidin. Ancak, başvurunuz burada durdurulduğundan, kesinlikle hizmet örnekleri de durdurulacaktır.

Son olarak, singleton sınıfında statik bir değişken kullanan bu yaklaşımın benim için çalıştığını belirtmek isterim.


7

onDestroy bu işe yaramaz yani her zaman hizmet çağrılmaz!

Örneğin: Sadece Eclipse'deki bir değişiklikle uygulamayı tekrar çalıştırın. Uygulama SIG: 9 kullanılarak zorla çıkar.


6

Öncelikle ActivityManager'ı kullanarak servise ulaşmaya çalışamazsınız. ( Burada tartışıldı )

Hizmetler kendi başlarına çalışabilir, bir Faaliyete veya her ikisine birden bağlı olabilir. Bir Etkinliğin Hizmetinizin çalışıp çalışmadığını kontrol etmenin yolu, hem Etkinliğin hem de Hizmetin anladığı yöntemleri bildirdiğiniz bir arabirim (Bağlayıcıyı genişleten) yapmaktır. Bunu, örneğin "isServiceRunning ()" gibi beyan ettiğiniz kendi Arayüzünüzü yaparak yapabilirsiniz. Daha sonra Etkinliğinizi Hizmetinize bağlayabilir, isServiceRunning () yöntemini çalıştırabilirsiniz, Hizmet çalışıp çalışmadığını kontrol eder ve Faaliyetinize bir boole döndürür.

Bu yöntemi, Hizmetinizi durdurmak veya başka bir şekilde etkileşimde bulunmak için de kullanabilirsiniz.

Bu öğreticiyi uygulamamda bu senaryoyu nasıl uygulayacağımı öğrenmek için kullandım .


3
Bu tartışma '12 / 26 / 07'de gerçekleşti. Ya bu yılın Temmuz ayı (yani gelecekte) ya da Android herkese açık olmadan önce. Her iki durumda da bu bana güvenmememi sağlıyor.
Tom

Bu tartışma 26 Aralık 2007'dir. Sanırım 14 Aralık 2007'de yayınlanan bir yayın öncesi sürümü ( developer.android.com/sdk/OLD_RELEASENOTES.html#m3-rc37a )
tartışıyorlar

6

Yine, beklemede olan hedefleri kullanan kişilerin daha temiz bulabileceği başka bir alternatif (örneğin 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);
}

CODEHizmetinizle ilişkili bekleyen hedefleri belirlemek için sınıfınızda özel olarak tanımladığınız bir sabit nerede .


1
Önceki cevabınızı birleştirin veya güncelleyin. Lütfen her gönderi için birden fazla yanıt göndermekten kaçının.
ChuongPham

Bu cevap genişletilebilir mi, yani KOD değeri hizmetle nasıl ilişkilendirilir?
Dave Nottage

Bağlam nereden alınır?
fesleğen

6

Aşağıda hepsini kapsayan zarif bir kesmek var Ifs. Bu yalnızca yerel hizmetler içindir.

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

Ve daha sonra:

    if(AService.isServiceCreated()){
        ...
    }else{
        startService(...);
    }

Bu tek sorun hizmet yapışkan bir hizmet ve kendini yeniden başlatın. Hizmet yeniden başlatıldığından, isServiceCreated () öğesini çağırmak, hizmet yeniden başladıktan sonra false değerini döndürür.
Mira_Cole

1
Hizmet kendini yeniden başlattığında onCreate çağrılmaz mı?
TheRealChx101

6

Xamarin C # sürümü:

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

İçin 'Bağlam'a ihtiyacınız var GetSystemService.
test

5

Burada verilen kullanım durumu için, sadece stopService()yöntemin dönüş değerini kullanabiliriz. trueBelirtilen hizmet varsa geri döner ve öldürülür. Yoksa geri döner false. Dolayısıyla, sonuç falsebaşka bir durumda geçerli hizmetin durdurulmuş olduğundan emin olabilirseniz hizmeti yeniden başlatabilirsiniz . Eğer bir göz varsa :) daha iyi olurdu bu .


5

Kotlin kullanan başka bir yaklaşım. Diğer kullanıcıların cevaplarından ilham aldı

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 uzantısı olarak

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

kullanım

context.isMyServiceRunning(MyService::class.java)

4

Kotlin'de, tamamlayıcı nesneye boolean değişkeni ekleyebilir ve değerini istediğiniz herhangi bir sınıftan kontrol edebilirsiniz:

companion object{
     var isRuning = false

}

Hizmet oluşturulduğunda ve yok edildiğinde değerini değiştirin

 override fun onCreate() {
        super.onCreate()
        isRuning = true
    }

override fun onDestroy() {
    super.onDestroy()
    isRuning = false
    }

3

Hizmet Alt Sınıfınızda Hizmetin durumunu aşağıda gösterildiği gibi almak için bir Statik Boole kullanın.

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 için aşağıdaki kodu kullanabilirsiniz.

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
}

Bu, çalışma kodunuzu değiştirmeden kullanabileceğiniz için test yazma için harika bir cevaptır.
Robert Liberatore

2

GeekQ'nun yanıtı Kotlin sınıfında. Teşekkürler 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
}

Arama

isMyServiceRunning(NewService::class.java)

6
ActivityManager.getRunningServicesAndroid O'dan beri kullanımdan kaldırıldı
Daniel Shatz

1

Aynı sınıf adına sahip birkaç hizmet olabilir.

Az önce iki uygulama oluşturdum. İlk uygulamanın paket adı com.example.mock. loremUygulamada çağrılan bir alt paket ve çağrılan bir hizmet oluşturdum Mock2Service. Yani tam adı com.example.mock.lorem.Mock2Service.

Sonra ikinci uygulamayı ve adlı bir hizmeti yarattım Mock2Service. İkinci uygulamanın paket adı com.example.mock.lorem. Hizmetin tam adı com.example.mock.lorem.Mock2Serviceda.

İşte benim logcat çıktı.

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

Daha iyi bir fikir karşılaştırmaktır ComponentNameçünkü örneklerini equals()ait ComponentNamepaket isimleri ve sınıf isimleri hem karşılaştırır. Ayrıca, bir cihazda aynı paket adına sahip iki uygulama bulunamaz.

Eşittir () yöntemi 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;
}

Bileşen Adı


1

Lütfen bu kodu kullanın.

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

Bu, bir iş parçacığı oluşturduğundan Intent Service hata ayıklaması için daha fazla geçerlidir, ancak düzenli hizmetler için de çalışabilir. Binging sayesinde bu konuyu buldum

Benim durumumda, hata ayıklayıcı ile oynadım ve iş parçacığı görünümü bulundu. MS Word'deki kurşun noktası simgesine benziyor. Her neyse, kullanmak için hata ayıklayıcı modunda olmanıza gerek yok. Süreci ve o düğmeyi tıklayın. Tüm Intent Services çalışırken en azından taklitçide görünecektir.


0

Hizmet başka bir işleme veya APK'ya aitse, ActivityManager'a dayalı çözümü kullanın.

Kaynağına erişiminiz varsa, statik alana dayalı olan çözümü kullanın. Ama bunun yerine bir boolean kullanarak bir Date nesnesi kullanmanızı öneririm. Hizmet çalışırken değerini 'şimdi' olarak güncelleyin ve işiniz bittiğinde değeri null olarak ayarlayın. Etkinlikten, boş değerinin veya tarihin çok eski olup olmadığını kontrol edebilirsiniz, bu da çalışmadığı anlamına gelir.

Hizmetinizden ilerleme durumu gibi daha fazla bilgi için yayınlandığını belirten yayın bildirimi de gönderebilirsiniz.


0

TheServiceClass içinde şunları tanımlar:

 public static Boolean serviceRunning = false;

Sonra onStartCommand (...)

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

    serviceRunning = true;
    ...
}

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

} 

Ardından, if(TheServiceClass.serviceRunning == true)herhangi bir sınıftan arayın .


4
Hizmet Android tarafından öldürülürse bu işe yaramaz.
Heisenberg

@ Heisenberg Bunu daha yeni yaşadım. Neden olmasın biliyor musun?
Tim

@Eisenberg, işletim sistemim OS tarafından öldürüldüğünde, hizmet yeniden başlatılır ve statik bool değerini true olarak ayarlar, ancak bunu aldıktan sonra yanlış raporlanır
Tim

ararsan bu işe yaramaz stopService. En azından Niyet hizmetleri için. onDestroy()hemen çağrılır, ancak onHandleIntent()yine de çalışır durumda
serggl

1
@Heisenberg Düşük bellek nedeniyle hizmeti öldürmeyecek olursanız, süreci de öldürmek mi gerekir?
android geliştirici

0

basit kullanım ile bağlama otomatik oluşturmayın - bkz. ps. ve güncelle ...

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

misal :

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

neden kullanmıyorsun? getRunningServices ()

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

Not: Bu yöntem yalnızca hizmet yönetimi türü kullanıcı arabirimlerinde hata ayıklama veya uygulama amaçlıdır.


ps. android dokümantasyon yanıltıcı herhangi bir şüpheyi ortadan kaldırmak için google tracker bir sorun açtı:

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

Bağlama hizmetinin aslında Hizmet önbellek bağlayıcıları aracılığıyla ActivityManager bağlayıcı aracılığıyla bir işlem başlattığını görebildiğimiz için, bağlantının hangi hizmetten sorumlu olduğunu izlerim ama bağlamanın sonucunu görebildiğimiz gibi:

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

işlem bağlayıcı yoluyla yapılır:

ServiceManager.getService("activity");

Sonraki:

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

bu EtkinlikThread'de ayarlanır:

 public final void bindApplication(...) {

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

bu yöntemde ActivityManagerService içinde çağrılır:

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

sonra:

 private HashMap<String, IBinder> getCommonServicesLocked() {

ancak "aktivite" sadece pencere paketi ve alarm yoktur ..

bu yüzden aramak için geri dönmeliyiz:

 return getIServiceManager().getService(name);

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

bu çağrı yapar:

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

hangi yol açar:

BinderInternal.getContextObject()

ve bu yerli yöntem ....

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

Ben dinlenme çağrı disseke kadar ben cevabımı askıya kadar c kazdık şimdi zaman yok.

ancak hizmetin çalışıp çalışmadığını denetlemenin en iyi yolu bağlama oluşturmaktır (bağlama oluşturulmamışsa hizmet mevcut değilse) - ve bağlama üzerinden hizmeti durumu hakkında sorgulamaktır (bu durumda kayıtlı dahili bayrağı kullanarak).

güncelleme 23.06.2018

bu ilginç buldum:

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

Kısacası :)

"Zaten bağlı bir hizmete bir bağlayıcı sağlayın. Bu yöntem eşzamanlıdır ve yoksa hedef hizmeti başlatmaz."

public IBinder peekService (Amaç hizmeti, String resolvedType, String callingPackage) RemoteException'ı atar;

*

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

*


Hizmet çalışmıyorsa bindResult (bindService yönteminin dönüş değeri) yanlış gelmez.
Shangeeth Sivan

0

Benim kotlin dönüşüm ActivityManager::getRunningServicestabanlı cevaplar. Bu işlevi bir etkinliğe

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

Hizmetinizin hala arka planda çalışıp çalışmadığını görmek için Android Geliştirici seçeneklerindeki bu seçenekleri kullanmanız mümkündür.

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

Sakin olun çocuklar :)

Bence en uygun çözüm, SharedPreferenceshizmetin çalışıp çalışmadığı hakkında bir anahtar / değer çifti tutmaktır .

Mantık çok düzdür; servis sınıfınızda istediğiniz herhangi bir konumda; hizmetin çalışıp çalışmadığı konusunda sizin için bayrak görevi görecek bir boolean değeri girin. Ardından, uygulamanızda istediğiniz yerde bu değeri okuyun.

Uygulamamda kullandığım örnek bir kod aşağıda:

Hizmet sınıfımda (Ses Akışı için bir hizmet), hizmet hazır olduğunda aşağıdaki kodu yürütürüm;

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

Sonra benim uygulama herhangi bir etkinliğinde, aşağıdaki kod yardımı ile hizmet durumunu kontrol ediyorum;

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

Özel izin yok, döngü yok ... Kolay yol, temiz çözüm :)

Daha fazla bilgiye ihtiyacınız varsa, lütfen bağlantıya bakın

Bu yardımcı olur umarım.


19
Hizmeti öldürdüklerinde sadece sizin için değeri kimsenin güncelleyemeyeceği
Gunnar Forsgren - Mobimation

servisini öldürdüğünde onDestroy () tetiklenir ve bu durumun güncellenmesi mümkündür
Jongz Puangput

5
@JongzPuangput, onDestroyhizmet öldürüldüğünde her zaman çağrılmaz. Örneğin, düşük bellek durumlarında hizmetlerimin onDestroyçağrılmadan öldüğünü gördüm .
Sam

@Sam O zaman ne denir?
Ruchir Baronia

2
@RuchirBaronia Hatırladığım kadarıyla, eşyalarınız öldürüldüğünde bildirim almıyorsunuz. Android'in uygulamaları gerektiği şekilde öldürmek için tasarlandığını ve uygulamaların herhangi bir zamanda bildirimde bulunulmaksızın öldürülecek şekilde tasarlanması gerektiğine inanıyorum.
Sam
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.