Como verifico se um serviço em segundo plano está em execução?
Quero uma atividade do Android que alterne o estado do serviço - ele permite ativá-lo se estiver desativado e desativado.
getRunningTasks()
, provavelmente será.
Como verifico se um serviço em segundo plano está em execução?
Quero uma atividade do Android que alterne o estado do serviço - ele permite ativá-lo se estiver desativado e desativado.
getRunningTasks()
, provavelmente será.
Respostas:
Eu tive o mesmo problema há pouco tempo. Como meu serviço era local, acabei simplesmente usando um campo estático na classe de serviço para alternar o estado, conforme descrito por hackbod aqui
EDIT (para o registro):
Aqui está a solução proposta pelo hackbod:
Se o código do cliente e do servidor fizer parte do mesmo .apk e você estiver vinculando ao serviço com um Intent concreto (um que especifique a classe de serviço exata), você poderá simplesmente fazer com que o seu serviço defina uma variável global quando estiver executando esse seu cliente pode verificar.
Deliberadamente, não temos uma API para verificar se um serviço está sendo executado porque, quase sem falhas, quando você deseja fazer algo assim, acaba com as condições de corrida em seu código.
onDestroy()
não é chamado. Portanto, a variável estática não pode ser atualizada nesse cenário, resultando em comportamento inconsistente.
Eu uso o seguinte de dentro de uma atividade:
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 eu chamo isso usando:
isMyServiceRunning(MyService.class)
Isso funciona de maneira confiável, porque se baseia nas informações sobre os serviços em execução fornecidos pelo sistema operacional Android por meio do ActivityManager # getRunningServices .
Todas as abordagens que usam eventos onDestroy ou onSometing, Binders ou variáveis estáticas não funcionarão de maneira confiável porque, como um desenvolvedor que você nunca conhece, quando o Android decide interromper seu processo ou qual dos retornos de chamada mencionados é chamado ou não. Observe a coluna "matável" na tabela de eventos do ciclo de vida na documentação do Android.
getRunningServices
está obsoleto. Esta resposta precisa de uma atualização para a versão mais recente.
Entendi!
Você DEVE solicitar startService()
que seu serviço seja registrado corretamente e a aprovação BIND_AUTO_CREATE
não será suficiente.
Intent bindIntent = new Intent(this,ServiceTask.class);
startService(bindIntent);
bindService(bindIntent,mConnection,0);
E agora a 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;
}
}
Um pequeno complemento é:
Meu objetivo é saber se um serviço está sendo executado sem realmente executá-lo, se não estiver sendo executado.
Chamar bindService ou chamar uma intenção que pode ser capturada pelo serviço não é uma boa ideia, pois iniciará o serviço se não estiver em execução.
Portanto, como o miracle2k sugeriu, o melhor é ter um campo estático na classe de serviço para saber se o serviço foi iniciado ou não.
Para torná-lo ainda mais limpo, sugiro transformar o serviço em um singleton com uma busca muito preguiçosa: ou seja, não há instanciação em toda a instância do singleton por métodos estáticos. O método estático getInstance do seu serviço / singleton apenas retorna a instância do singleton se ele tiver sido criado. Mas, na verdade, ele não inicia nem instancia o próprio singleton. O serviço é iniciado apenas através dos métodos normais de início do serviço.
Seria então mais limpo modificar o padrão de design singleton para renomear o método getInstance confuso para algo como o isInstanceCreated() : boolean
método.
O código será parecido com:
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
Essa solução é elegante, mas só é relevante se você tiver acesso à classe de serviço e apenas para as classes do aplicativo / pacote do serviço. Se suas aulas estiverem fora do aplicativo / pacote de serviço, você poderá consultar o ActivityManager com as limitações sublinhadas por Pieter-Jan Van Robays.
Você pode usar isso (ainda não tentei isso, mas espero que funcione):
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();
}
O método startService retorna um objeto ComponentName se já houver um serviço em execução. Caso contrário, nulo será retornado.
Consulte o resumo público ComponentName startService (serviço de intenção) .
Acho que não é como checar, porque está iniciando o serviço, para que você possa adicionar stopService(someIntent);
o código.
if(startService(someIntent) != null)
isso verifica isso, IsserviceRunning
mas também reproduz um novo serviço.
/**
* 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;
}
Uma extração de documentos do Android :
Como sendBroadcast (Intent) , mas se houver algum receptor para o Intent, essa função irá bloquear e enviá-los imediatamente antes de retornar.
Pense nesse hack como "pingando" o arquivoService
. Como podemos transmitir de forma síncrona, podemos transmitir e obter um resultado de forma síncrona , no thread da interface do usuário.
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;
}
}
O vencedor em muitos aplicativos é, obviamente, um campo booleano estático no serviço definido como true
in Service.onCreate()
e false
in Service.onDestroy()
porque é muito mais simples.
Modifiquei levemente uma das soluções apresentadas acima, mas passei a classe em vez de um nome genérico de string, para garantir a comparação de strings que saem do mesmo método 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 depois
Boolean isServiceRunning = ServiceTools.isServiceRunning(
MainActivity.this.getApplicationContext(),
BackgroundIntentService.class);
Class<? extends Service>
A maneira correta de verificar se um serviço está sendo executado é simplesmente perguntar. Implemente um BroadcastReceiver em seu serviço que responda aos pings de suas atividades. Registre o BroadcastReceiver quando o serviço iniciar e cancele o registro quando o serviço for destruído. Na sua atividade (ou em qualquer componente), envie uma intenção de transmissão local para o serviço e, se responder, você sabe que está em execução. Observe a diferença sutil entre ACTION_PING e ACTION_PONG no código abaixo.
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;
}
}
};
}
Eu só quero adicionar uma nota à resposta de @Snicolas. As etapas a seguir podem ser usadas para verificar a interrupção do serviço com / sem chamar onDestroy()
.
onDestroy()
chamado: Vá para Configurações -> Aplicativo -> Serviços em execução -> Selecione e pare seu serviço.
onDestroy()
não chamado: Vá para Configurações -> Aplicativo -> Gerenciar aplicativos -> Selecione e "Force Stop" seu aplicativo em que o serviço está sendo executado. No entanto, como seu aplicativo é parado aqui, definitivamente as instâncias de serviço também serão interrompidas.
Por fim, gostaria de mencionar que a abordagem mencionada lá usando uma variável estática na classe singleton está funcionando para mim.
onDestroy
nem sempre é chamado no serviço, portanto isso é inútil!
Por exemplo: Basta executar o aplicativo novamente com uma alteração do Eclipse. O aplicativo é encerrado à força usando SIG: 9.
Antes de tudo, você não deve tentar acessar o serviço usando o ActivityManager. (Discutido aqui )
Os serviços podem ser executados por conta própria, vinculados a uma Atividade ou a ambos. A maneira de fazer check-in de uma Atividade se o seu Serviço está em execução ou não é criando uma interface (que estende o Fichário) em que você declara métodos que tanto a Atividade quanto o Serviço entendem. Você pode fazer isso criando sua própria interface, onde declara, por exemplo, "isServiceRunning ()". Em seguida, você pode vincular sua Atividade ao seu Serviço, executar o método isServiceRunning (), o Serviço verificará por si próprio se está em execução ou não e retornará um booleano à sua Atividade.
Você também pode usar esse método para interromper seu serviço ou interagir com ele de outra maneira.
Usei este tutorial para aprender como implementar esse cenário no meu aplicativo.
Novamente, outra alternativa que as pessoas podem achar mais limpa se usarem intenções pendentes (por exemplo, com o 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);
}
Onde CODE
é uma constante que você define em particular na sua classe para identificar as intenções pendentes associadas ao seu serviço.
Abaixo está um hack elegante que cobre todo o Ifs
. Isto é apenas para serviços locais.
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 depois, mais tarde:
if(AService.isServiceCreated()){
...
}else{
startService(...);
}
Versão 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
.
Para o caso de uso fornecido aqui, podemos simplesmente usar o stopService()
valor de retorno do método. Retorna true
se houver o serviço especificado e for morto. Caso contrário, ele retorna false
. Portanto, você pode reiniciar o serviço se o resultado for false
outro, pois o serviço atual foi interrompido. :) Seria melhor se você desse uma olhada nisso .
Outra abordagem usando o kotlin. Inspirado nas respostas de outros usuários
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 }
}
Como extensão 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)
No kotlin, você pode adicionar variáveis booleanas no objeto complementar e verificar seu valor em qualquer classe que desejar:
companion object{
var isRuning = false
}
Altere seu valor quando o serviço for criado e destruído
override fun onCreate() {
super.onCreate()
isRuning = true
}
override fun onDestroy() {
super.onDestroy()
isRuning = false
}
Na sua subclasse de serviço Use um booleano estático para obter o estado do serviço, conforme demonstrado abaixo.
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)
}
}
}
Para o kotlin, você pode usar o código abaixo.
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
}
A resposta do geekQ, mas na classe Kotlin. Obrigado 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
}
A chamada
isMyServiceRunning(NewService::class.java)
ActivityManager.getRunningServices
está obsoleto desde o Android O
Pode haver vários serviços com o mesmo nome de classe.
Acabei de criar dois aplicativos. O nome do pacote do primeiro aplicativo é com.example.mock
. Criei um subpacote chamado lorem
no aplicativo e um serviço chamado Mock2Service
. Portanto, seu nome completo é com.example.mock.lorem.Mock2Service
.
Então eu criei o segundo aplicativo e um serviço chamado Mock2Service
. O nome do pacote do segundo aplicativo é com.example.mock.lorem
. O nome completo do serviço écom.example.mock.lorem.Mock2Service
também é.
Aqui está minha saída do 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
A melhor idéia é comparar ComponentName
casos, porque equals()
deComponentName
compara ambos os nomes de pacotes e nomes de classe. E não pode haver dois aplicativos com o mesmo nome de pacote instalados em um dispositivo.
O método equals () de 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;
}
Por favor, use este código.
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;
}
Isso se aplica mais à depuração do Serviço de Intenção, pois eles geram um encadeamento, mas também podem funcionar para serviços regulares. Encontrei este tópico graças ao Binging
No meu caso, brinquei com o depurador e encontrei a visualização de threads. Parece o ícone do marcador no MS Word. De qualquer forma, você não precisa estar no modo de depurador para usá-lo. Clique no processo e clique nesse botão. Quaisquer Serviços de Intenção aparecerão enquanto estiverem em execução, pelo menos no emulador.
Se o serviço pertencer a outro processo ou APK, use a solução com base no ActivityManager.
Se você tiver acesso à sua origem, basta usar a solução com base em um campo estático. Mas, em vez disso, usando um booleano, sugiro usar um objeto Date. Enquanto o serviço estiver em execução, basta atualizar seu valor para 'agora' e, quando terminar, defina-o como nulo. A partir da atividade, você pode verificar se é nulo ou se a data é muito antiga, o que significa que não está em execução.
Você também pode enviar uma notificação de transmissão do seu serviço, indicando que está sendo exibida mais informações, como progresso.
Dentro de TheServiceClass, defina:
public static Boolean serviceRunning = false;
Em seguida, em onStartCommand (...)
public int onStartCommand(Intent intent, int flags, int startId) {
serviceRunning = true;
...
}
@Override
public void onDestroy()
{
serviceRunning = false;
}
Em seguida, ligue if(TheServiceClass.serviceRunning == true)
de qualquer classe.
stopService
. Pelo menos para serviços Intent. onDestroy()
será chamado imediatamente, mas onHandleIntent()
ainda estará funcionando
uso simples vincular com não criar auto - veja ps. e atualizar ...
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);
exemplo:
Intent bindIntent = new Intent(context, Class<Service>);
boolean bindResult = context.bindService(bindIntent, ServiceConnection, 0);
por que não usar? getRunningServices ()
List<ActivityManager.RunningServiceInfo> getRunningServices (int maxNum)
Return a list of the services that are currently running.
Nota: este método destina-se apenas à depuração ou implementação de interfaces de usuário do tipo gerenciamento de serviços.
ps. A documentação do Android é enganosa. Abri um problema no Google Tracker para eliminar qualquer dúvida:
https://issuetracker.google.com/issues/68908332
como podemos ver, o serviço de ligação realmente chama uma transação através do fichário ActivityManager através de fichários de cache de serviço - identifico qual serviço é responsável pela ligação, mas como podemos ver o resultado da ligação é:
int res = ActivityManagerNative.getDefault().bindService(...);
return res != 0;
a transação é feita através do fichário:
ServiceManager.getService("activity");
Próximo:
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
isso é definido no ActivityThread via:
public final void bindApplication(...) {
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
}
isso é chamado no ActivityManagerService no método:
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
...
thread.bindApplication(... , getCommonServicesLocked(),...)
então:
private HashMap<String, IBinder> getCommonServicesLocked() {
mas não há "atividade" apenas pacote de janela e alarme ..
então precisamos voltar a ligar para:
return getIServiceManager().getService(name);
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
isso faz a chamada através de:
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
o que leva a :
BinderInternal.getContextObject()
e este é o método 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();
agora não tenho tempo para cavar c, até dissecar a chamada de descanso e suspender minha resposta.
mas a melhor maneira de verificar se o serviço está em execução é criar a ligação (se a ligação não foi criada, o serviço não existe) - e consultar o serviço sobre seu estado através da ligação (usando sinalizador interno armazenado no estado).
eu achei aqueles interessantes:
/**
* 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;
}
em resumo :)
"Forneça um fichário para um serviço já vinculado. Este método é síncrono e não iniciará o serviço de destino se ele não estiver presente."
public IBinder peekService (serviço Intent, String resolvedType, String chamandoPackage) lança 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;
}
*
Minha conversão kotlin das ActivityManager::getRunningServices
respostas baseadas. Coloque essa função em uma atividade -
private fun isMyServiceRunning(serviceClass: Class<out Service>) =
(getSystemService(ACTIVITY_SERVICE) as ActivityManager)
.getRunningServices(Int.MAX_VALUE)
?.map { it.service.className }
?.contains(serviceClass.name) ?: false
É possível usar essas opções nas opções do Desenvolvedor Android para ver se seu serviço ainda está sendo executado em segundo plano.
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.
Calma galera ... :)
Eu acho que a solução mais adequada é manter um par de valores-chave SharedPreferences
sobre se o serviço está sendo executado ou não.
A lógica é muito direta; em qualquer posição desejada em sua classe de serviço; coloque um valor booleano que atuará como um sinalizador para você sobre se o serviço está sendo executado ou não. Em seguida, leia esse valor onde quiser no seu aplicativo.
Um código de exemplo que estou usando no meu aplicativo está abaixo:
Na minha classe de serviço (um serviço para fluxo de áudio), executo o código a seguir quando o serviço está ativo;
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();
}
Em qualquer atividade do meu aplicativo, estou verificando o status do serviço com a ajuda do código a seguir;
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);
}
Sem permissões especiais, sem loops ... Maneira fácil, solução limpa :)
Se você precisar de informações adicionais, consulte o link
Espero que isto ajude.
onDestroy
nem sempre é chamado quando o serviço é interrompido . Por exemplo, vi meus serviços serem mortos em situações de pouca memória sem onDestroy
serem chamados.