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.
getRunningTasks()
, mungkin akan.
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.
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:
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.
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:
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.
getRunningServices
sudah usang. Jawaban ini membutuhkan pembaruan untuk versi yang lebih baru.
Oke!
Anda HARUS memanggil startService()
layanan Anda untuk didaftarkan dengan benar dan lewat BIND_AUTO_CREATE
tidak 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;
}
}
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:
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.
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.
if(startService(someIntent) != null)
itu akan memeriksa itu IsserviceRunning
tetapi itu juga akan memainkan layanan baru.
/**
* 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;
}
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 true
dalam Service.onCreate()
dan ke false
dalam Service.onDestroy()
karena itu jauh lebih sederhana.
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);
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.
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;
}
}
};
}
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.
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.
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.
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 CODE
konstanta yang Anda tetapkan secara pribadi di kelas Anda untuk mengidentifikasi maksud yang tertunda terkait dengan layanan Anda.
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(...);
}
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;
}
GetSystemService
.
Untuk case-use yang diberikan di sini kita cukup menggunakan nilai pengembalian stopService()
metode. Itu kembali true
jika ada layanan yang ditentukan dan itu terbunuh. Jika tidak kembali false
. Jadi, Anda dapat memulai kembali layanan jika hasilnya false
lain, dipastikan bahwa layanan saat ini telah dihentikan. :) Akan lebih baik jika Anda melihat ini .
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)
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
}
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)
}
}
}
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
}
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)
ActivityManager.getRunningServices
sudah ditinggalkan sejak Android O
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 lorem
dalam 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.Mock2Service
juga.
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 ComponentName
contoh karena equals()
dari ComponentName
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
.
@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;
}
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;
}
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.
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.
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.
stopService
. Setidaknya untuk layanan Intent. onDestroy()
akan dipanggil segera, tetapi onHandleIntent()
masih akan berjalan
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).
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;
}
*
Konversi kotlin saya dari ActivityManager::getRunningServices
jawaban 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
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.
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;
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.
onDestroy
tidak selalu dipanggil saat layanan terbunuh. Sebagai contoh, saya telah melihat layanan saya terbunuh dalam situasi memori rendah tanpa onDestroy
dipanggil.