Come posso verificare se è in esecuzione un servizio in background?
Voglio un'attività Android che commuti lo stato del servizio: mi consente di attivarlo se è spento e spento se è acceso.
getRunningTasks()
, probabilmente lo sarà.
Come posso verificare se è in esecuzione un servizio in background?
Voglio un'attività Android che commuti lo stato del servizio: mi consente di attivarlo se è spento e spento se è acceso.
getRunningTasks()
, probabilmente lo sarà.
Risposte:
Ho avuto lo stesso problema non molto tempo fa. Dato che il mio servizio era locale, ho finito semplicemente usando un campo statico nella classe di servizio per attivare lo stato, come descritto da hackbod qui
EDIT (per la cronaca):
Ecco la soluzione proposta da hackbod:
Se il tuo codice client e server fa parte dello stesso .apk e stai vincolando il servizio con un intento concreto (uno che specifica l'esatta classe di servizio), allora puoi semplicemente impostare il tuo servizio impostando una variabile globale quando lo sta eseguendo il tuo cliente può controllare.
Non abbiamo deliberatamente un'API per verificare se un servizio è in esecuzione perché, quasi a colpo sicuro, quando vuoi fare qualcosa del genere finisci con le condizioni di competizione nel tuo codice.
onDestroy()
non viene chiamato. Pertanto la variabile statica non può essere aggiornata in uno scenario di questo tipo con conseguente comportamento incoerente.
Uso all'interno di un'attività quanto segue:
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;
}
E lo chiamo usando:
isMyServiceRunning(MyService.class)
Funziona in modo affidabile, perché si basa sulle informazioni relative ai servizi in esecuzione fornite dal sistema operativo Android tramite ActivityManager # getRunningServices .
Tutti gli approcci che utilizzano eventi onDestroy o onSometing o leganti o variabili statiche non funzioneranno in modo affidabile perché come sviluppatore non si sa mai, quando Android decide di interrompere il processo o quale dei callback menzionati viene chiamato o meno. Nota la colonna "killable" nella tabella degli eventi del ciclo di vita nella documentazione di Android.
getRunningServices
è deprecato. Questa risposta richiede un aggiornamento per la versione più recente.
Fatto!
È NECESSARIO chiamare startService()
per la corretta registrazione del servizio e il passaggio BIND_AUTO_CREATE
non sarà sufficiente.
Intent bindIntent = new Intent(this,ServiceTask.class);
startService(bindIntent);
bindService(bindIntent,mConnection,0);
E ora la classe 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;
}
}
Un piccolo complemento è:
Il mio obiettivo è sapere se un servizio è in esecuzione senza realmente eseguirlo se non è in esecuzione.
Chiamare bindService o chiamare un intento che può essere colto dal servizio non è una buona idea, in quanto avvierà il servizio se non è in esecuzione.
Quindi, come suggerito da miracle2k, la cosa migliore è avere un campo statico nella classe di servizio per sapere se il servizio è stato avviato o meno.
Per renderlo ancora più pulito, suggerisco di trasformare il servizio in un singleton con un recupero molto pigro: cioè, non vi è alcuna istanza di tutta l' istanza singleton attraverso metodi statici. Il metodo statico getInstance del tuo servizio / singleton restituisce l'istanza del singleton solo se è stata creata. Ma in realtà non avvia o istanzia il singleton stesso. Il servizio viene avviato solo tramite i normali metodi di avvio del servizio.
Sarebbe quindi ancora più pulito modificare il modello di progettazione singleton per rinominare il metodo confuso getInstance in qualcosa di simile al isInstanceCreated() : boolean
metodo.
Il codice sarà simile a:
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
Questa soluzione è elegante, ma è rilevante solo se si ha accesso alla classe di servizio e solo per le classi è l'app / pacchetto del servizio. Se le tue classi sono al di fuori dell'app / pacchetto di servizi, puoi interrogare ActivityManager con le limitazioni sottolineate da Pieter-Jan Van Robays.
Puoi usarlo (non l'ho ancora provato, ma spero che funzioni):
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();
}
Il metodo startService restituisce un oggetto ComponentName se esiste già un servizio in esecuzione. In caso contrario, verrà restituito null.
Vedi abstract pubblico ComponentName startService (servizio Intent) .
Penso che non sia come controllare, perché sta avviando il servizio, quindi puoi aggiungerlo stopService(someIntent);
sotto il codice.
if(startService(someIntent) != null)
verificherà ciò, IsserviceRunning
ma riprodurrà anche un nuovo servizio.
/**
* 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;
}
Un estratto dai documenti Android :
Come sendBroadcast (Intent) , ma se ci sono ricevitori per l'Intent questa funzione li bloccherà e li spedirà immediatamente prima di tornare.
Pensa a questo hack come "ping" ilService
. Dal momento che possiamo trasmettere in modo sincrono, possiamo trasmettere e ottenere un risultato in modo sincrono , sul thread dell'interfaccia utente.
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;
}
}
Il vincitore in molte applicazioni è, ovviamente, un campo booleano statico sul servizio che è impostato su true
in Service.onCreate()
e in false
in Service.onDestroy()
perché è molto più semplice.
Ho leggermente modificato una delle soluzioni presentate sopra, ma passando la classe anziché un nome di stringa generico, per essere sicuro di confrontare le stringhe che escono dallo stesso metodo 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;
}
}
e poi
Boolean isServiceRunning = ServiceTools.isServiceRunning(
MainActivity.this.getApplicationContext(),
BackgroundIntentService.class);
Class<? extends Service>
Il modo corretto per verificare se un servizio è in esecuzione è semplicemente richiederlo. Implementa un BroadcastReceiver nel tuo servizio che risponda ai ping delle tue attività. Registrare BroadcastReceiver all'avvio del servizio e annullare la registrazione quando il servizio viene distrutto. Dalla tua attività (o qualsiasi componente), invia una trasmissione locale al servizio e se risponde, sai che è in esecuzione. Nota la sottile differenza tra ACTION_PING e ACTION_PONG nel codice seguente.
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;
}
}
};
}
Voglio solo aggiungere una nota alla risposta di @Snicolas. I seguenti passaggi possono essere utilizzati per controllare il servizio di arresto con / senza chiamare onDestroy()
.
onDestroy()
chiamato: vai in Impostazioni -> Applicazione -> Servizi in esecuzione -> Seleziona e interrompi il servizio.
onDestroy()
non chiamato: vai in Impostazioni -> Applicazione -> Gestisci applicazioni -> Seleziona e "Forza arresto" l'applicazione in cui è in esecuzione il servizio. Tuttavia, poiché l'applicazione viene arrestata qui, anche le istanze del servizio verranno arrestate.
Infine, vorrei menzionare che l'approccio menzionato lì utilizzando una variabile statica nella classe singleton funziona per me.
onDestroy
non è sempre chiamato nel servizio quindi questo è inutile!
Ad esempio: esegui di nuovo l'app con una modifica da Eclipse. L'applicazione viene forzatamente chiusa utilizzando SIG: 9.
Prima di tutto non devi provare a raggiungere il servizio utilizzando ActivityManager. (discusso qui )
I servizi possono essere eseguiti da soli, essere associati a un'attività o entrambi. Il modo per verificare un'attività se il servizio è in esecuzione o meno consiste nel creare un'interfaccia (che estende Binder) in cui si dichiarano metodi comprensibili sia per l'attività che per il servizio. Puoi farlo creando la tua interfaccia in cui dichiari ad esempio "isServiceRunning ()". È quindi possibile associare l'attività al servizio, eseguire il metodo isServiceRunning (), il servizio verificherà se è in esecuzione o meno e restituisce un valore booleano all'attività.
È inoltre possibile utilizzare questo metodo per interrompere il servizio o interagire con esso in un altro modo.
Ho usato questo tutorial per imparare come implementare questo scenario nella mia applicazione.
Ancora una volta, un'altra alternativa che le persone potrebbero trovare più pulite se usano intenti in sospeso (ad esempio con 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);
}
Dov'è CODE
una costante che definisci privatamente nella tua classe per identificare gli intenti in sospeso associati al tuo servizio.
Di seguito è riportato un elegante trucco che copre tutto Ifs
. Questo è solo per servizi locali.
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;
}
}
E poi in seguito:
if(AService.isServiceCreated()){
...
}else{
startService(...);
}
Versione 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
.
Per il caso d'uso indicato qui possiamo semplicemente utilizzare il stopService()
valore di ritorno del metodo. Restituisce true
se esiste il servizio specificato e viene ucciso. Altrimenti ritorna false
. Quindi è possibile riavviare il servizio se il risultato è false
diverso, si è certi che il servizio corrente è stato interrotto. :) Sarebbe meglio se si dispone di uno sguardo a questo .
Un altro approccio con kotlin. Ispirato nelle risposte di altri utenti
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 }
}
Come estensione 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 }
}
uso
context.isMyServiceRunning(MyService::class.java)
In kotlin puoi aggiungere una variabile booleana nell'oggetto companion e verificarne il valore da qualsiasi classe desideri:
companion object{
var isRuning = false
}
Cambiarlo valore quando il servizio viene creato e distrutto
override fun onCreate() {
super.onCreate()
isRuning = true
}
override fun onDestroy() {
super.onDestroy()
isRuning = false
}
Nella sottoclasse del servizio Utilizzare un valore booleano statico per ottenere lo stato del servizio come mostrato di seguito.
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)
}
}
}
Per kotlin, puoi usare il codice qui sotto.
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
}
La risposta di geekQ ma nella classe di Kotlin. Grazie 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
}
La chiamata
isMyServiceRunning(NewService::class.java)
ActivityManager.getRunningServices
è obsoleto da Android O
Possono esserci diversi servizi con lo stesso nome di classe.
Ho appena creato due app. Il nome del pacchetto della prima app è com.example.mock
. Ho creato un subpackage chiamato lorem
nell'app e un servizio chiamato Mock2Service
. Quindi il suo nome completo ècom.example.mock.lorem.Mock2Service
.
Quindi ho creato la seconda app e un servizio chiamato Mock2Service
. Il nome del pacchetto della seconda app è com.example.mock.lorem
. Anche il nome completo del servizio è com.example.mock.lorem.Mock2Service
.
Ecco il mio output logcat.
03-27 12:02:19.985: D/TAG(32155): Mock-01: com.example.mock.lorem.Mock2Service
03-27 12:02:33.755: D/TAG(32277): Mock-02: com.example.mock.lorem.Mock2Service
Un'idea migliore è quella di confrontare le ComponentName
istanze a causa equals()
dei ComponentName
confronti sia dei nomi dei pacchetti che dei nomi delle classi. E non ci possono essere due app con lo stesso nome di pacchetto installato su un dispositivo.
Il metodo equals () di 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;
}
Si prega di utilizzare questo codice
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;
}
Questo vale maggiormente per il debug del servizio di intenti poiché generano un thread, ma può funzionare anche per i servizi regolari. Ho trovato questa discussione grazie a Binging
Nel mio caso, ho giocato con il debugger e ho trovato la vista thread. Sembra un po 'come l'icona del punto elenco in MS Word. Ad ogni modo, non è necessario essere in modalità debugger per usarlo. Fare clic sul processo e fare clic su quel pulsante. Qualsiasi Intent Services verrà visualizzato mentre sono in esecuzione, almeno sull'emulatore.
Se il servizio appartiene a un altro processo o APK, utilizzare la soluzione basata su ActivityManager.
Se hai accesso alla sua fonte, usa semplicemente la soluzione basata su un campo statico. Ma invece usando un booleano suggerirei di usare un oggetto Date. Mentre il servizio è in esecuzione, basta aggiornare il suo valore su "now" e quando termina impostarlo su null. Dall'attività è possibile verificare se il suo valore nullo o la data è troppo vecchia, il che significa che non è in esecuzione.
Puoi anche inviare una notifica di trasmissione dal tuo servizio indicando che sono in esecuzione ulteriori informazioni come i progressi.
All'interno di TheServiceClass definisci:
public static Boolean serviceRunning = false;
Quindi in onStartCommand (...)
public int onStartCommand(Intent intent, int flags, int startId) {
serviceRunning = true;
...
}
@Override
public void onDestroy()
{
serviceRunning = false;
}
Quindi, chiama if(TheServiceClass.serviceRunning == true)
da qualsiasi classe.
stopService
. Almeno per i servizi Intent. onDestroy()
verrà chiamato immediatamente, ma onHandleIntent()
continuerà a funzionare
uso semplice associa con non creare auto - vedi ps. e aggiorna ...
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);
esempio :
Intent bindIntent = new Intent(context, Class<Service>);
boolean bindResult = context.bindService(bindIntent, ServiceConnection, 0);
perché non usare? getRunningServices ()
List<ActivityManager.RunningServiceInfo> getRunningServices (int maxNum)
Return a list of the services that are currently running.
Nota: questo metodo è destinato esclusivamente al debug o all'implementazione delle interfacce utente del tipo di gestione del servizio.
ps. la documentazione di Android è fuorviante, ho aperto un problema sul tracker di Google per eliminare qualsiasi dubbio:
https://issuetracker.google.com/issues/68908332
come possiamo vedere il servizio bind in realtà richiama una transazione tramite il binder ActivityManager attraverso i binder della cache del servizio - non tengo traccia di quale servizio sia responsabile dell'associazione ma come possiamo vedere il risultato per il bind è:
int res = ActivityManagerNative.getDefault().bindService(...);
return res != 0;
la transazione viene effettuata tramite raccoglitore:
ServiceManager.getService("activity");
Il prossimo:
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
questo è impostato in ActivityThread tramite:
public final void bindApplication(...) {
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
}
questo viene chiamato in ActivityManagerService nel metodo:
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
...
thread.bindApplication(... , getCommonServicesLocked(),...)
poi:
private HashMap<String, IBinder> getCommonServicesLocked() {
ma non c'è "attività" solo pacchetto finestra e allarme.
quindi dobbiamo tornare a chiamare:
return getIServiceManager().getService(name);
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
questo fa chiamare attraverso:
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
che conduce a :
BinderInternal.getContextObject()
e questo è un metodo nativo ....
/**
* 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();
non ho tempo ora di scavare in c così fino a quando non seziono la chiamata di riposo sospendo la mia risposta.
ma il modo migliore per verificare se il servizio è in esecuzione è creare un bind (se il bind non viene creato, il servizio non esiste) e interrogare il servizio sul suo stato attraverso il bind (usando il flag interno memorizzato sullo stato).
ho trovato quelli interessanti:
/**
* 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;
}
in breve :)
"Fornire un raccoglitore a un servizio già associato. Questo metodo è sincrono e non avvierà il servizio di destinazione se non è presente."
public IBinder peekService (Servizio intento, String resolvedType, String callingPackage) genera 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;
}
*
La mia conversione kotlin delle ActivityManager::getRunningServices
risposte basate. Metti questa funzione in un'attività-
private fun isMyServiceRunning(serviceClass: Class<out Service>) =
(getSystemService(ACTIVITY_SERVICE) as ActivityManager)
.getRunningServices(Int.MAX_VALUE)
?.map { it.service.className }
?.contains(serviceClass.name) ?: false
È possibile utilizzare queste opzioni dalle opzioni per gli sviluppatori Android per vedere se il servizio è ancora in esecuzione in background.
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.
Vacci piano ragazzi ... :)
Penso che la soluzione più adatta sia tenere una coppia chiave-valore SharedPreferences
se il servizio è in esecuzione o meno.
La logica è molto semplice; in qualsiasi posizione desiderata nella tua classe di servizio; inserisci un valore booleano che fungerà da flag per te se il servizio è in esecuzione o meno. Quindi leggi questo valore dove vuoi nella tua applicazione.
Di seguito è riportato un codice di esempio che sto utilizzando nella mia app:
Nella mia classe di servizio (A service for Audio Stream), eseguo il codice seguente quando il servizio è attivo;
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();
}
Quindi in qualsiasi attività della mia applicazione, sto controllando lo stato del servizio con l'aiuto del seguente codice;
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);
}
Nessuna autorizzazione speciale, nessun loop ... Modo semplice, soluzione pulita :)
Se hai bisogno di ulteriori informazioni, consulta il link
Spero che sia di aiuto.
onDestroy
non viene sempre chiamato quando il servizio viene interrotto . Ad esempio, ho visto i miei servizi uccisi in situazioni di memoria insufficiente senza onDestroy
essere chiamato.