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.
android
android-service
Lebah
sumber
sumber
getRunningTasks()
, mungkin akan.Jawaban:
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:
sumber
onDestroy()
tidak dipanggil. Jadi variabel statis tidak dapat diperbarui dalam skenario seperti itu yang mengakibatkan perilaku tidak konsisten.Saya menggunakan yang berikut dari dalam suatu kegiatan:
Dan saya menyebutnya menggunakan:
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.
sumber
getRunningServices
sudah usang. Jawaban ini membutuhkan pembaruan untuk versi yang lebih baru.Oke!
Anda HARUS memanggil
startService()
layanan Anda untuk didaftarkan dengan benar dan lewatBIND_AUTO_CREATE
tidak akan cukup.Dan sekarang kelas ServiceTools:
sumber
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() : boolean
metode tersebut.Kode akan terlihat seperti:
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.
sumber
Anda dapat menggunakan ini (saya belum mencoba ini, tapi saya harap ini berhasil):
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.sumber
if(startService(someIntent) != null)
itu akan memeriksa ituIsserviceRunning
tetapi itu juga akan memainkan layanan baru.sumber
Ekstrak dari Android docs:
Pikirkan hack ini sebagai "ping"
Service
. Karena kami dapat menyiarkan secara sinkron, kami dapat menyiarkan dan mendapatkan hasilnya secara sinkron , di utas UI.Service
Activity
Pemenang dalam banyak aplikasi, tentu saja, bidang boolean statis pada layanan yang diatur ke
true
dalamService.onCreate()
dan kefalse
dalamService.onDestroy()
karena itu jauh lebih sederhana.sumber
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()
lalu
sumber
Class<? extends Service>
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.
sumber
Saya hanya ingin menambahkan catatan ke jawaban oleh @Snicolas. Langkah-langkah berikut dapat digunakan untuk memeriksa layanan berhenti dengan / tanpa menelepon
onDestroy()
.onDestroy()
disebut: Buka Pengaturan -> Aplikasi -> Menjalankan Layanan -> Pilih dan hentikan layanan Anda.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.
sumber
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.
sumber
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.
sumber
Sekali lagi, alternatif lain yang orang mungkin temukan lebih bersih jika mereka menggunakan niat yang tertunda (misalnya dengan
AlarmManager
:Di mana
CODE
konstanta yang Anda tetapkan secara pribadi di kelas Anda untuk mengidentifikasi maksud yang tertunda terkait dengan layanan Anda.sumber
Di bawah ini adalah hack elegan yang mencakup semua
Ifs
. Ini hanya untuk layanan lokal.Dan kemudian:
sumber
Versi Xamarin C #:
sumber
GetSystemService
.Untuk case-use yang diberikan di sini kita cukup menggunakan nilai pengembalian
stopService()
metode. Itu kembalitrue
jika ada layanan yang ditentukan dan itu terbunuh. Jika tidak kembalifalse
. Jadi, Anda dapat memulai kembali layanan jika hasilnyafalse
lain, dipastikan bahwa layanan saat ini telah dihentikan. :) Akan lebih baik jika Anda melihat ini .sumber
Pendekatan lain menggunakan kotlin. Terinspirasi dalam jawaban pengguna lain
Sebagai ekstensi kotlin
Pemakaian
sumber
Di kotlin Anda dapat menambahkan variabel boolean di objek pendamping dan memeriksa nilainya dari kelas yang Anda inginkan:
Ubah nilainya saat layanan dibuat dan dimusnahkan
sumber
Dalam Sub-Kelas Layanan Anda Gunakan Boolean Statis untuk mendapatkan status Layanan seperti yang ditunjukkan di bawah ini.
MyService.kt
MainActivity.kt
sumber
Untuk kotlin, Anda dapat menggunakan kode di bawah ini.
sumber
Panggilan
sumber
ActivityManager.getRunningServices
sudah ditinggalkan sejak Android OMungkin 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 disebutlorem
dalam aplikasi dan layanan yang disebutMock2Service
. Jadi nama yang sepenuhnya memenuhi syarat adalahcom.example.mock.lorem.Mock2Service
.Lalu saya membuat aplikasi kedua dan layanan yang disebut
Mock2Service
. Nama paket aplikasi kedua adalahcom.example.mock.lorem
. Nama layanan yang sepenuhnya memenuhi syaratcom.example.mock.lorem.Mock2Service
juga.Ini adalah keluaran logcat saya.
Sebuah ide yang lebih baik adalah untuk membandingkan
ComponentName
contoh karenaequals()
dariComponentName
membandingkan 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
.Nama komponen
sumber
Silakan gunakan kode ini.
sumber
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.
sumber
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.
sumber
Di dalam TheServiceClass, tentukan:
Lalu di onStartCommand (...)
Kemudian, teleponlah
if(TheServiceClass.serviceRunning == true)
dari kelas mana saja.sumber
stopService
. Setidaknya untuk layanan Intent.onDestroy()
akan dipanggil segera, tetapionHandleIntent()
masih akan berjalanikat penggunaan yang sederhana dengan jangan membuat otomatis- lihat ps. dan perbarui ...contoh:
mengapa tidak menggunakan getRunningServices ()
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:
transaksi dilakukan melalui binder:
lanjut:
ini diatur dalam ActivityThread via:
ini disebut dalam ActivityManagerService dalam metode:
kemudian:
tetapi tidak ada "aktivitas" hanya paket jendela dan alarm ..
jadi kita perlu kembali untuk menelepon:
ini membuat panggilan melalui:
yang mengarah ke:
dan ini adalah metode asli ....
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:
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;
sumber
Konversi kotlin saya dari
ActivityManager::getRunningServices
jawaban berdasarkan. Tempatkan fungsi ini dalam aktivitas-sumber
Dimungkinkan bagi Anda untuk menggunakan opsi ini dari opsi Pengembang Android untuk melihat apakah layanan Anda masih berjalan di latar belakang.
sumber
Tenang saja kawan ... :)
Saya pikir solusi yang paling cocok adalah memegang pasangan nilai kunci
SharedPreferences
tentang 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;
Kemudian dalam aktivitas apa pun aplikasi saya, saya sedang memeriksa status layanan dengan bantuan kode berikut;
Tidak ada izin khusus, tidak ada loop ... Cara mudah, solusi bersih :)
Jika Anda memerlukan informasi tambahan, silakan merujuk tautan
Semoga ini membantu.
sumber
onDestroy
tidak selalu dipanggil saat layanan terbunuh. Sebagai contoh, saya telah melihat layanan saya terbunuh dalam situasi memori rendah tanpaonDestroy
dipanggil.