Bagaimana cara memeriksa apakah suatu layanan berjalan di Android?

936

Bagaimana cara saya memeriksa apakah layanan latar belakang berjalan?

Saya ingin aktivitas Android yang mengubah status layanan - ini memungkinkan saya untuk mengaktifkannya jika mati dan mati jika dinyalakan.

Lebah
sumber
2
Lihatlah panduan bahasa Jerman ini .
Markus Peröbner
17
jawaban yang benar adalah di bawah ini dan bukan yang ditandai: stackoverflow.com/a/5921190/2369122
toidiu
1
@ toidiu Jika itu belum seperti Nerfed getRunningTasks(), mungkin akan.
Kevin Krumwiede
menggunakan fungsi getSystemService () Anda dapat mengambil semua layanan yang berjalan. loop melalui itu dan periksa layanan Anda ada dalam daftar di sini Anda dapat melihat sampel kecil wiki.workassis.com/android-check-the-service-is-running
Bikesh M

Jawaban:

292

Saya memiliki masalah yang sama belum lama ini. Karena layanan saya bersifat lokal, saya akhirnya hanya menggunakan bidang statis di kelas layanan untuk beralih status, seperti yang dijelaskan oleh hackbod di sini

EDIT (untuk catatan):

Inilah solusi yang diusulkan oleh hackbod:

Jika klien dan kode server Anda adalah bagian dari .apk yang sama dan Anda mengikat ke layanan dengan Intent yang konkret (yang menentukan kelas layanan yang tepat), maka Anda bisa meminta layanan Anda mengatur variabel global ketika menjalankan klien Anda dapat memeriksa.

Kami sengaja tidak memiliki API untuk memeriksa apakah suatu layanan berjalan karena, hampir tanpa kegagalan, ketika Anda ingin melakukan sesuatu seperti itu, Anda berakhir dengan kondisi lomba dalam kode Anda.

miracle2k
sumber
27
@ Peracerier, solusi yang Anda rujuk memerlukan memulai layanan dan saya pikir solusi fleksibel terbaik harus memungkinkan Anda untuk memeriksa apakah suatu layanan berjalan tanpa memulainya.
Tom
17
Bagaimana jika layanan dihentikan oleh sistem, bagaimana Anda mendeteksi itu dan beralih variabel Anda?
jmng
23
Ketika aplikasi terbunuh, layanan yang telah dimulai juga dimatikan tetapi layanan onDestroy()tidak dipanggil. Jadi variabel statis tidak dapat diperbarui dalam skenario seperti itu yang mengakibatkan perilaku tidak konsisten.
faizal
5
@faizal Bukankah variabel statis juga akan diinternisasi ulang, sehingga pengaturannya kembali ke nilai default yang menunjukkan layanan tidak lagi berjalan?
PabloC
12
@faizal, Layanan lokal bukan proses yang terpisah, jadi jika layanan dimatikan maka aplikasi juga akan mati.
Sever
1674

Saya menggunakan yang berikut dari dalam suatu kegiatan:

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

Dan saya menyebutnya menggunakan:

isMyServiceRunning(MyService.class)

Ini berfungsi dengan baik, karena didasarkan pada informasi tentang menjalankan layanan yang disediakan oleh sistem operasi Android melalui ActivityManager # getRunningServices .

Semua pendekatan yang menggunakan onDestroy atau onSometing events atau Binder atau variabel statis tidak akan berfungsi dengan andal karena sebagai pengembang Anda tidak pernah tahu, kapan Android memutuskan untuk membunuh proses Anda atau panggilan balik mana yang disebut atau tidak. Harap perhatikan kolom "dapat dibunuh" di tabel siklus hidup dalam dokumentasi Android.

geekQ
sumber
85
Terima kasih atas solusi ini. Saya ingin menambahkan: Alih-alih "com.example.MyService" lebih elegan untuk menggunakan MyService.class.getName ()
peter.bartos
10
Secara pribadi, saya menggunakan bidang statis. Meskipun menggunakan getRunningServices () adalah solusi yang lebih tangguh, saya percaya ada dua solusi ini sebagai tradeoff antara ketahanan dan efisiensi / kesederhanaan. Jika Anda perlu sering memeriksa apakah suatu layanan berjalan, mengulangi layanan yang berpotensi berjalan 30+ tidak terlalu ideal. Kasus langka dari layanan yang dihancurkan oleh sistem dapat ditangani mungkin dengan blok coba / tangkap atau dengan menggunakan START_STICKY.
robguinness
80
Tidak, itu bukan jawaban yang tepat karena itu juga tertulis dalam dokumen: "Catatan: metode ini hanya ditujukan untuk debugging atau mengimplementasikan antarmuka pengguna tipe manajemen layanan." Itu tidak dimaksudkan untuk aliran kontrol!
seb
40
Orang-orang merasa elegan harus melalui semua itu untuk memeriksa apakah server berjalan?
Rui Marques
81
Memulai Android O , getRunningServicessudah usang. Jawaban ini membutuhkan pembaruan untuk versi yang lebih baru.
poring91
75

Oke!

Anda HARUS memanggil startService()layanan Anda untuk didaftarkan dengan benar dan lewat BIND_AUTO_CREATEtidak akan cukup.

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

Dan sekarang kelas 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;
     }
}
Kevin Parker
sumber
Ini hanya akan menampilkan layanan sistem, bukan ?! Jadi layanan lokal saya dikecualikan dari daftar dan saya akan mendapatkan palsu; (
Ewoks
Ini berfungsi dengan layanan eksternal, untuk layanan lokal cukup jelas jika Anda menjalankan.
Kevin Parker
11
Maaf tapi saya harus mengatakan itu adalah jawaban yang sangat konyol..Kenapa itu sangat jelas ?!
Ewoks
10
Tidak jelas apa maksudmu di sini ... Siapa yang berbicara tentang menabrak sama sekali ?! Saya tidak tertarik menabraknya. Layanan dapat dimulai, dihentikan, mungkin itu layanan maksud dan itu akan berhenti sendiri ketika selesai ... Pertanyaannya adalah bagaimana mengetahui apakah masih berjalan atau tidak setelah 3 menit misalnya.
Ewoks
1
Tidak benar memberi kesan bahwa layanan terikat juga harus dimulai. TIDAK. Bind auto create melakukan apa yang dikatakannya. Ini akan membuat (dan karenanya "memulai") layanan jika layanan tersebut belum berjalan.
Sreedevi J
57

Komplemen kecil adalah:

Tujuan saya adalah untuk mengetahui apakah suatu layanan berjalan tanpa benar-benar menjalankannya jika tidak berjalan.

Memanggil bindService atau memanggil niat yang dapat ditangkap oleh layanan bukanlah ide yang baik karena akan memulai layanan jika tidak berjalan.

Jadi, seperti yang disarankan miracle2k, yang terbaik adalah memiliki bidang statis di kelas layanan untuk mengetahui apakah layanan telah dimulai atau tidak.

Untuk membuatnya lebih bersih, saya sarankan untuk mengubah layanan dalam singleton dengan pengambilan yang sangat sangat malas: yaitu, tidak ada instantiasi pada semua instance singleton melalui metode statis. Metode getInstance statis dari layanan Anda / singleton hanya mengembalikan instance dari singleton jika telah dibuat. Tapi itu sebenarnya tidak memulai atau memulai singleton itu sendiri. Layanan hanya dimulai melalui metode mulai layanan normal.

Maka akan lebih bersih untuk memodifikasi pola desain tunggal untuk mengubah nama metode getInstance yang membingungkan menjadi sesuatu seperti isInstanceCreated() : booleanmetode tersebut.

Kode akan terlihat seperti:

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

Solusi ini elegan, tetapi hanya relevan jika Anda memiliki akses ke kelas layanan dan hanya untuk kelas di samping aplikasi / paket layanan. Jika kelas Anda di luar aplikasi / paket layanan maka Anda dapat meminta ActivityManager dengan batasan yang digarisbawahi oleh Pieter-Jan Van Robays.

Snicolas
sumber
32
Ini cacat. onDestroy tidak dijamin dipanggil.
Pacerier
8
Ketika sistem rendah pada memori, layanan Anda akan terbunuh secara otomatis tanpa panggilan ke onDestroy Anda, itulah sebabnya saya mengatakan bahwa ini cacat.
Pacerier
17
@ Peracerier, tetapi jika sistem membunuh prosesnya, maka flag instance akan tetap mendapatkan reset. Saya menduga bahwa ketika penerima selanjutnya dimuat (memposting sistem mematikan layanan) flag statis 'instance' akan dibuat kembali sebagai nol.
Tom
2
Setidaknya lebih baik daripada iterasi melalui semua layanan di isMyServiceRunning yang benar-benar menunda hal-hal jika dilakukan pada setiap rotasi perangkat :)
Gunnar Forsgren - Mobimation
1
Variabel instance Anda tidak boleh dinyatakan final, jika tidak, variabel tersebut tidak dapat disetel atau dibatalkan oleh metode onCreate () atau onDestroy ().
k2col
27

Anda dapat menggunakan ini (saya belum mencoba ini, tapi saya harap ini berhasil):

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

Metode startService mengembalikan objek ComponentName jika ada layanan yang sudah berjalan. Jika tidak, null akan dikembalikan.

Lihat StartService ComponentName abstrak publik (layanan Intent) .

Ini tidak seperti memeriksa saya pikir, karena ini memulai layanan, sehingga Anda dapat menambahkan di stopService(someIntent);bawah kode.

Keenan Gebze
sumber
11
Tidak persis apa yang dikatakan dokumen. Menurut tautan Anda: "Pengembalian Jika layanan sedang dimulai atau sudah berjalan, ComponentName dari layanan aktual yang dimulai dikembalikan; selain itu jika layanan tidak ada, null dikembalikan."
Gabriel
Pemikiran yang bagus ... tetapi tidak sesuai dengan situasi saat ini.
Code_Life
5
itu bukan cara yang tepat, karena ketika IDE memicu if(startService(someIntent) != null)itu akan memeriksa itu IsserviceRunningtetapi itu juga akan memainkan layanan baru.
Chintan Khetiya
Seperti yang dinyatakan, jika Anda menghentikan layanan setelah kontrol ini akan berguna untuk masalah ini. Tetapi mengapa memulai dan menghentikan layanan dengan gratis?
Taner
6
ini akan memulai layanan, bukan? Hanya ingin memeriksa status layanan alih-alih memulainya ...
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;
}
JR
sumber
21

Ekstrak dari Android docs:

Seperti sendBroadcast (Intent) , tetapi jika ada penerima untuk Intent, fungsi ini akan memblokir dan segera mengirimkannya sebelum kembali.

Pikirkan hack ini sebagai "ping"Service . Karena kami dapat menyiarkan secara sinkron, kami dapat menyiarkan dan mendapatkan hasilnya secara sinkron , di utas UI.

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

Pemenang dalam banyak aplikasi, tentu saja, bidang boolean statis pada layanan yang diatur ke truedalam Service.onCreate()dan ke falsedalam Service.onDestroy()karena itu jauh lebih sederhana.

peterchaula
sumber
Ini adalah solusi yang jauh lebih baik daripada yang diterima, yang gagal jika Android membunuh layanan karena metode variabel global masih akan menunjukkan bahwa layanan ini berjalan ketika sebenarnya tidak lagi. Trik broadcast ping-pong sinkron ini sebenarnya adalah metode yang HANYA dapat diandalkan untuk memeriksa apakah suatu layanan masih hidup. Itu sendiri memungkinkan Anda untuk hanya MEMINTA layanan jika ada. Jika ia menjawab maka layanannya hidup dan berjalan, jika belum, ia belum dimulai atau dimatikan, baik secara terprogram atau oleh sistem untuk memulihkan memori.
Phoenix Diungkap
13

Saya telah sedikit memodifikasi salah satu solusi yang disajikan di atas, tetapi melewati kelas alih-alih nama string generik, untuk memastikan untuk membandingkan string yang keluar dari metode yang sama 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;
    }
}

lalu

Boolean isServiceRunning = ServiceTools.isServiceRunning(
                    MainActivity.this.getApplicationContext(),
                    BackgroundIntentService.class);
loretoparisi
sumber
untuk menjadi lebih tegas, Anda dapat mengubah param kelas menjadiClass<? extends Service>
silentsudo
11

Cara yang tepat untuk memeriksa apakah suatu layanan berjalan adalah dengan menanyakannya. Terapkan BroadcastReceiver di layanan Anda yang merespons ping dari aktivitas Anda. Daftarkan BroadcastReceiver ketika layanan dimulai, dan batalkan registrasi ketika layanan dihancurkan. Dari aktivitas Anda (atau komponen apa pun), kirim maksud siaran lokal ke layanan dan jika merespons, Anda tahu itu sedang berjalan. Perhatikan perbedaan halus antara ACTION_PING dan ACTION_PONG dalam kode di bawah ini.

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;
            }
        }
    };
}
Ben H
sumber
1
Saya sebenarnya suka pendekatan ini. Ini sedikit kode bijak tetapi akan selalu berhasil. Saya tidak melihat niat siaran yang ditinggalkan dalam waktu dekat :)
ShellDude
8

Saya hanya ingin menambahkan catatan ke jawaban oleh @Snicolas. Langkah-langkah berikut dapat digunakan untuk memeriksa layanan berhenti dengan / tanpa menelepon onDestroy().

  1. onDestroy() disebut: Buka Pengaturan -> Aplikasi -> Menjalankan Layanan -> Pilih dan hentikan layanan Anda.

  2. onDestroy()tidak dipanggil: Buka Pengaturan -> Aplikasi -> Kelola Aplikasi -> Pilih dan "Paksa Berhenti" aplikasi Anda di mana layanan Anda berjalan. Namun, karena aplikasi Anda dihentikan di sini, maka pasti instans layanan juga akan dihentikan.

Akhirnya, saya ingin menyebutkan bahwa pendekatan yang disebutkan di sana menggunakan variabel statis di kelas singleton bekerja untuk saya.

Paul
sumber
7

onDestroy tidak selalu dipanggil dalam layanan jadi ini tidak berguna!

Misalnya: Cukup jalankan aplikasi lagi dengan satu perubahan dari Eclipse. Aplikasi secara paksa keluar menggunakan SIG: 9.

Kevin Parker
sumber
6

Pertama-tama Anda tidak perlu mencoba untuk mencapai layanan dengan menggunakan ActivityManager. (Dibahas di sini )

Layanan dapat berjalan sendiri, terikat pada suatu Aktivitas atau keduanya. Cara untuk memeriksa dalam suatu Aktivitas apakah Layanan Anda berjalan atau tidak adalah dengan membuat antarmuka (yang meluas Binder) tempat Anda mendeklarasikan metode yang dipahami oleh keduanya, Activity dan Layanan. Anda dapat melakukan ini dengan membuat Antarmuka sendiri di mana Anda mendeklarasikan misalnya "isServiceRunning ()". Anda kemudian dapat mengikat Aktivitas Anda ke Layanan Anda, menjalankan metode isServiceRunning (), Layanan akan memeriksa sendiri apakah itu berjalan atau tidak dan mengembalikan boolean ke Aktivitas Anda.

Anda juga dapat menggunakan metode ini untuk menghentikan Layanan Anda atau berinteraksi dengannya dengan cara lain.

Saya menggunakan tutorial ini untuk mempelajari cara Menerapkan skenario ini di aplikasi saya.

Pieter-Jan Van Robays
sumber
3
Diskusi itu berlangsung pada '12 / 26/07 '. Entah itu bulan Juli tahun ini (yaitu di masa depan), atau itu sebelum Android bahkan publik. Apa pun itu yang membuat saya tidak percaya.
Tom
Diskusi itu dari 26 Desember 2007. Mereka sedang mendiskusikan versi pra-rilis yang saya rasa ( developer.android.com/sdk/OLD_RELEASENOTES.html#m3-rc37a ) yang dirilis pada 14 Desember 2007.
ingh.am
6

Sekali lagi, alternatif lain yang orang mungkin temukan lebih bersih jika mereka menggunakan niat yang tertunda (misalnya dengan 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);
}

Di mana CODEkonstanta yang Anda tetapkan secara pribadi di kelas Anda untuk mengidentifikasi maksud yang tertunda terkait dengan layanan Anda.

Snicolas
sumber
1
Menggabungkan atau memperbarui jawaban Anda sebelumnya. Harap jangan memposting lebih dari satu jawaban per posting.
ChuongPham
Dapatkah jawaban ini diperluas, yaitu bagaimana seseorang menghubungkan nilai untuk KODE dengan layanan?
Dave Nottage
Di mana mendapatkan konteks?
basil
6

Di bawah ini adalah hack elegan yang mencakup semua Ifs. Ini hanya untuk layanan lokal.

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

Dan kemudian:

    if(AService.isServiceCreated()){
        ...
    }else{
        startService(...);
    }
TheRealChx101
sumber
Satu-satunya masalah dengan ini adalah jika layanan tersebut adalah layanan Sticky dan restart sendiri. Memanggil ke isServiceCreated () akan mengembalikan false setelah layanan dimulai kembali karena mInstance akan menjadi nol.
Mira_Cole
1
Bukankah onCreate akan dipanggil saat layanan restart sendiri?
TheRealChx101
6

Versi Xamarin C #:

private bool isMyServiceRunning(System.Type cls)
{
    ActivityManager manager = (ActivityManager)GetSystemService(Context.ActivityService);

    foreach (var service in manager.GetRunningServices(int.MaxValue)) {
        if (service.Service.ClassName.Equals(Java.Lang.Class.FromType(cls).CanonicalName)) {
            return true;
        }
    }
    return false;
}
Nima
sumber
Anda memerlukan ´Context` untuk GetSystemService.
pengujian
5

Untuk case-use yang diberikan di sini kita cukup menggunakan nilai pengembalian stopService()metode. Itu kembali truejika ada layanan yang ditentukan dan itu terbunuh. Jika tidak kembali false. Jadi, Anda dapat memulai kembali layanan jika hasilnya falselain, dipastikan bahwa layanan saat ini telah dihentikan. :) Akan lebih baik jika Anda melihat ini .

Rahul Raveendran
sumber
5

Pendekatan lain menggunakan kotlin. Terinspirasi dalam jawaban pengguna lain

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

Sebagai ekstensi kotlin

fun Context.isMyServiceRunning(serviceClass: Class<*>): Boolean {
    val manager = this.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    return manager.getRunningServices(Integer.MAX_VALUE)
            .any { it.service.className == serviceClass.name }
}

Pemakaian

context.isMyServiceRunning(MyService::class.java)
Oscar Emilio Perez Martinez
sumber
4

Di kotlin Anda dapat menambahkan variabel boolean di objek pendamping dan memeriksa nilainya dari kelas yang Anda inginkan:

companion object{
     var isRuning = false

}

Ubah nilainya saat layanan dibuat dan dimusnahkan

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

override fun onDestroy() {
    super.onDestroy()
    isRuning = false
    }
Mohamed Saber
sumber
3

Dalam Sub-Kelas Layanan Anda Gunakan Boolean Statis untuk mendapatkan status Layanan seperti yang ditunjukkan di bawah ini.

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)
        }
    }
}
EdgeDev
sumber
3

Untuk kotlin, Anda dapat menggunakan kode di bawah ini.

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
}
PA Gosai
sumber
Ini adalah jawaban yang bagus untuk menulis tes, karena Anda dapat menggunakannya tanpa mengubah kode kerja Anda.
Robert Liberatore
2

Tanggapan geekQ tetapi di kelas Kotlin. Terima kasih 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
}

Panggilan

isMyServiceRunning(NewService::class.java)
Luis Eduardo Moreno
sumber
6
ActivityManager.getRunningServicessudah ditinggalkan sejak Android O
Daniel Shatz
1

Mungkin ada beberapa layanan dengan nama kelas yang sama.

Saya baru saja membuat dua aplikasi. Nama paket aplikasi pertama adalah com.example.mock. Saya membuat sub paket yang disebut loremdalam aplikasi dan layanan yang disebut Mock2Service. Jadi nama yang sepenuhnya memenuhi syarat adalah com.example.mock.lorem.Mock2Service.

Lalu saya membuat aplikasi kedua dan layanan yang disebut Mock2Service. Nama paket aplikasi kedua adalah com.example.mock.lorem. Nama layanan yang sepenuhnya memenuhi syarat com.example.mock.lorem.Mock2Servicejuga.

Ini adalah keluaran logcat saya.

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

Sebuah ide yang lebih baik adalah untuk membandingkan ComponentNamecontoh karena equals()dari ComponentNamemembandingkan kedua nama paket dan nama kelas. Dan tidak mungkin ada dua aplikasi dengan nama paket yang sama yang diinstal pada perangkat.

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

Nama komponen

Maksim Dmitriev
sumber
1

Silakan gunakan kode ini.

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;
    }
Nikunj Sorathiya
sumber
0

Ini berlaku lebih ke arah debugging Intent Service karena mereka menelurkan utas, tetapi juga bisa berfungsi untuk layanan reguler. Saya menemukan utas ini berkat Binging

Dalam kasus saya, saya bermain-main dengan debugger dan menemukan tampilan utas. Agak terlihat seperti ikon titik peluru di MS Word. Bagaimanapun, Anda tidak harus berada dalam mode debugger untuk menggunakannya. Klik pada proses dan klik tombol itu. Setiap Layanan Intent akan muncul saat sedang berjalan, setidaknya pada emulator.

Joe Plante
sumber
0

Jika layanan tersebut milik proses lain atau APK gunakan solusi berdasarkan ActivityManager.

Jika Anda memiliki akses ke sumbernya, cukup gunakan solusi berdasarkan bidang statis. Tapi alih-alih menggunakan boolean saya sarankan menggunakan objek Date. Saat layanan berjalan, perbarui nilainya menjadi 'sekarang' dan setelah selesai setel ke nol. Dari aktivitas, Anda dapat memeriksa apakah nol atau tanggal terlalu lama yang berarti tidak berjalan.

Anda juga dapat mengirim pemberitahuan siaran dari layanan Anda yang menunjukkan bahwa sedang menjalankan info lebih lanjut seperti kemajuan.

FranMowinckel
sumber
0

Di dalam TheServiceClass, tentukan:

 public static Boolean serviceRunning = false;

Lalu di onStartCommand (...)

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

    serviceRunning = true;
    ...
}

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

} 

Kemudian, teleponlah if(TheServiceClass.serviceRunning == true)dari kelas mana saja.

Badr
sumber
4
Ini tidak berfungsi jika layanan Anda terbunuh oleh Android.
Heisenberg
@ Heisenberg Saya baru saja mengalaminya sendiri. Apakah kamu tahu mengapa tidak?
Tim
@Heisenberg ketika aplikasi saya dibunuh oleh OS, layanan tidak me-restart dan mengatur bool statis menjadi true, tetapi setelah mendapatkannya dilaporkan salah
Tim
ini tidak akan berfungsi jika Anda menelepon stopService. Setidaknya untuk layanan Intent. onDestroy()akan dipanggil segera, tetapi onHandleIntent()masih akan berjalan
serggl
1
@ Heisenberg Tidak akan membunuh layanan karena memori yang rendah juga berarti membunuh prosesnya?
pengembang android
0

ikat penggunaan yang sederhana dengan jangan membuat otomatis - lihat ps. dan perbarui ...

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

contoh:

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

mengapa tidak menggunakan getRunningServices ()

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

Catatan: metode ini hanya dimaksudkan untuk debugging atau mengimplementasikan antarmuka pengguna tipe manajemen layanan.


ps. Dokumentasi android menyesatkan saya telah membuka masalah di google tracker untuk menghilangkan keraguan:

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

karena kita dapat melihat layanan bind benar-benar menjalankan transaksi melalui binder ActivityManager melalui binder cache Layanan - saya tidak melacak layanan mana yang bertanggung jawab untuk mengikat tetapi karena kita dapat melihat hasil untuk bind adalah:

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

transaksi dilakukan melalui binder:

ServiceManager.getService("activity");

lanjut:

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

ini diatur dalam ActivityThread via:

 public final void bindApplication(...) {

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

ini disebut dalam ActivityManagerService dalam metode:

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

kemudian:

 private HashMap<String, IBinder> getCommonServicesLocked() {

tetapi tidak ada "aktivitas" hanya paket jendela dan alarm ..

jadi kita perlu kembali untuk menelepon:

 return getIServiceManager().getService(name);

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

ini membuat panggilan melalui:

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

yang mengarah ke:

BinderInternal.getContextObject()

dan ini adalah metode asli ....

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

saya tidak punya waktu sekarang untuk menggali c sehingga sampai saya membedah panggilan sisa saya menangguhkan jawaban saya.

tetapi cara terbaik untuk memeriksa apakah layanan berjalan adalah membuat bind (jika bind tidak menciptakan layanan tidak ada) - dan meminta layanan tentang statusnya melalui bind (menggunakan flag internal yang tersimpan pada statusnya).

perbarui 23.06.2018

saya menemukan yang menarik:

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

pendeknya :)

"Berikan pengikat ke layanan yang sudah terikat. Metode ini sinkron dan tidak akan memulai layanan target jika tidak ada."

public IBinder peekService (layanan Intent, String resolvedType, String callingPackage) melempar 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;
}

*

ceph3us
sumber
bindResult (nilai balik metode bindService) tidak datang sebagai false jika layanan tidak berjalan.
Shangeeth Sivan
0

Konversi kotlin saya dari ActivityManager::getRunningServicesjawaban berdasarkan. Tempatkan fungsi ini dalam aktivitas-

private fun isMyServiceRunning(serviceClass: Class<out Service>) =
    (getSystemService(ACTIVITY_SERVICE) as ActivityManager)
        .getRunningServices(Int.MAX_VALUE)
        ?.map { it.service.className }
        ?.contains(serviceClass.name) ?: false
Gulshan
sumber
-2

Dimungkinkan bagi Anda untuk menggunakan opsi ini dari opsi Pengembang Android untuk melihat apakah layanan Anda masih berjalan di latar belakang.

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.
Haomin
sumber
-5

Tenang saja kawan ... :)

Saya pikir solusi yang paling cocok adalah memegang pasangan nilai kunci SharedPreferencestentang apakah layanan ini berjalan atau tidak.

Logika sangat lurus; pada posisi yang diinginkan di kelas layanan Anda; beri nilai boolean yang akan bertindak sebagai bendera untuk Anda tentang apakah layanan berjalan atau tidak. Kemudian baca nilai ini di mana pun Anda inginkan dalam aplikasi Anda.

Contoh kode yang saya gunakan di aplikasi saya adalah di bawah ini:

Di kelas Layanan saya (Layanan untuk Aliran Audio), saya menjalankan kode berikut saat layanan menyala;

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

Kemudian dalam aktivitas apa pun aplikasi saya, saya sedang memeriksa status layanan dengan bantuan kode berikut;

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

Tidak ada izin khusus, tidak ada loop ... Cara mudah, solusi bersih :)

Jika Anda memerlukan informasi tambahan, silakan merujuk tautan

Semoga ini membantu.

Taner
sumber
19
Hanya saja tidak ada yang akan memperbarui nilai untuk Anda ketika mereka membunuh layanan
Gunnar Forsgren - Mobimation
ketika membunuh layanan diDestroy () akan dipicu dan itu mungkin untuk memperbarui negaranya
Jongz Puangput
5
@JongzPuangput, onDestroytidak selalu dipanggil saat layanan terbunuh. Sebagai contoh, saya telah melihat layanan saya terbunuh dalam situasi memori rendah tanpa onDestroydipanggil.
Sam
@ Sam Lalu apa yang akan dipanggil?
Ruchir Baronia
2
@RuchirBaronia Sejauh yang saya ingat, Anda tidak diberi tahu saat barang Anda terbunuh. Saya percaya Android dirancang untuk membunuh aplikasi sesuai kebutuhan, dan aplikasi harus dirancang untuk diharapkan untuk dibunuh kapan saja tanpa pemberitahuan.
Sam