Como verificar se um serviço está sendo executado no Android?

936

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.

Abelha
fonte
2
Confira este guia em alemão .
Markus Peröbner 01/08/19
17
a resposta correta é baixo e não o marcou: stackoverflow.com/a/5921190/2369122
toidiu
1
@toidiu Se isso ainda não foi nerfado getRunningTasks(), provavelmente será.
21415 Kevin Krumwiede
Usando a função getSystemService (), você pode recuperar todos os serviços em execução. loop-lo e verificar a exist seu serviço na lista aqui você pode ver uma pequena amostra wiki.workassis.com/android-check-the-service-is-running
Bikesh M

Respostas:

292

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.

miracle2k
fonte
27
@Pacerier, a solução mencionada requer o início do serviço e acho que a melhor solução flexível deve permitir que você verifique se um serviço está sendo executado sem iniciá-lo.
Tom
17
E se o serviço for interrompido pelo sistema, como você detecta isso e alterna sua variável?
Jmng 28/05
23
Quando o aplicativo é finalizado, o serviço iniciado também é finalizado, mas o serviço onDestroy()não é chamado. Portanto, a variável estática não pode ser atualizada nesse cenário, resultando em comportamento inconsistente.
faizal
5
@faizal A variável estática também não seria reinicializada, retornando-a ao valor padrão que indica que o serviço não está mais em execução?
PabloC
12
@faizal, o Serviço local não é um processo separado, portanto, se o serviço for morto, o aplicativo também matará.
Sever
1674

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.

geekQ
fonte
85
Obrigado por esta solução. Eu gostaria de acrescentar: Em vez disso "com.example.MyService" é mais elegante para usar MyService.class.getName ()
peter.bartos
10
Pessoalmente, eu usei um campo estático. Embora o uso de getRunningServices () seja uma solução mais robusta, acredito que nessas duas soluções haja uma troca entre robustez e eficiência / simplicidade. Se você precisar verificar com frequência se um serviço está sendo executado, fazer um loop entre mais de 30 serviços em execução não é o ideal. O raro caso de um serviço ser destruído pelo sistema pode ser tratado talvez por um bloco try / catch ou usando START_STICKY.
robguinness
80
Não, não é a resposta certa, porque também está escrita nos documentos: "Nota: este método é destinado apenas à depuração ou implementação de interfaces de usuário do tipo gerenciamento de serviços". Não é para fluxo de controle!
seb
40
As pessoas acham elegante ter que passar por tudo isso para verificar se um servidor está em execução?
Rui Marques
81
Iniciando o Android O , getRunningServicesestá obsoleto. Esta resposta precisa de uma atualização para a versão mais recente.
poring91
75

Entendi!

Você DEVE solicitar startService()que seu serviço seja registrado corretamente e a aprovação BIND_AUTO_CREATEnã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;
     }
}
Kevin Parker
fonte
Isso listará apenas os serviços do sistema, não ?! Portanto, meu serviço local é excluído da lista e eu vou ser falso; (
Ewoks
Isso funciona com serviços externos, pois os serviços locais são bastante óbvios se você estiver executando.
Kevin Parker
11
Desculpe, mas eu preciso dizer que é uma resposta super boba ... Por que é super óbvia ?!
Ewoks
10
Não está claro o que você quer dizer aqui ... Quem estava falando sobre cair ?! Eu não sou interessante em bater nele. O serviço pode ser iniciado, parado, talvez tenha sido um serviço intencional e será interrompido por si só quando for concluído ... A questão é como saber se ele ainda está em execução ou não após 3 minutos, por exemplo.
Ewoks
1
É incorreto dar a impressão de que um serviço vinculado também deve ser iniciado. NÃO. A criação automática de vínculos faz exatamente o que diz. Ele criará (e, portanto, "iniciará") o serviço se o serviço ainda não estiver em execução.
Sreedevi J
57

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() : booleanmé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.

Snicolas
fonte
32
Isso é falho. Não é garantido que o onDestroy seja chamado.
Pacerier
8
Quando o sistema está com pouca memória, seu serviço será interrompido automaticamente sem uma ligação para o seu onDestroy, e é por isso que digo que isso é defeituoso.
Pacerier
17
@Pacerier, mas se o sistema concluir o processo, o sinalizador da instância ainda será redefinido. Eu estou supondo que quando o próximo receptor for carregado (após o sistema matar o serviço), o sinalizador estático 'instance' será recriado como nulo.
Tom
2
Pelo menos melhor do que a iteração através de todos esses serviços em isMyServiceRunning que realmente atrasa coisas se feito em cada rotação do dispositivo :)
Gunnar Forsgren - Mobimation
1
Sua variável de instância não deve ser declarada final, caso contrário, não poderá ser configurada ou nula pelos métodos onCreate () ou onDestroy ().
K2col
27

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.

Keenan Gebze
fonte
11
Não é exatamente o que dizem os documentos. De acordo com o seu link: "Retornos Se o serviço estiver sendo iniciado ou já estiver em execução, o ComponentName do serviço real iniciado foi retornado; caso contrário, se o serviço não existir, será retornado nulo."
11742 Gabriel
Bom pensamento ... mas não se encaixa na situação atual.
Code_Life 18/09/12
5
não é a maneira correta, porque quando o IDE dispara, if(startService(someIntent) != null)isso verifica isso, IsserviceRunningmas também reproduz um novo serviço.
Chintan Khetiya
Como afirmado, se você parar o serviço após esse controle, será útil para esse problema. Mas por que iniciar e parar um serviço por nada?
Taner
6
isso iniciará o serviço, não é? Só quero verificar o status do serviço em vez de iniciá-lo ...
Raptor
26
/**
 * Check if the service is Running 
 * @param serviceClass the class of the Service
 *
 * @return true if the service is running otherwise false
 */
public boolean checkServiceRunning(Class<?> serviceClass){
    ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE))
    {
        if (serviceClass.getName().equals(service.service.getClassName()))
        {
            return true;
        }
    }
    return false;
}
JR
fonte
21

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 truein Service.onCreate()e falsein Service.onDestroy()porque é muito mais simples.

peterchaula
fonte
Essa é uma solução muito melhor do que a aceita, que falha se o Android matar o serviço, pois o método da variável global ainda indicaria que o serviço está sendo executado quando realmente não está mais. Esse truque de transmissão de ping-pong síncrono é realmente o ÚNICO método confiável para verificar se um serviço está ativo. Somente ele permite que você simplesmente solicite o serviço, se ele estiver lá. Se responder, o serviço está ativo e em execução; caso contrário, ele não foi iniciado ou foi encerrado, programaticamente ou pelo sistema para recuperar memória.
PhoenixRevealed
13

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);
Loretoparisi
fonte
para ser mais no lado estrita pode mudar de classe param paraClass<? extends Service>
silentsudo
11

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;
            }
        }
    };
}
Ben H
fonte
1
Eu realmente gosto dessa abordagem. É um pouco pesado em termos de código, mas sempre funcionará. Não vejo intenções de transmissão a ser preterida em breve :)
ShellDude
8

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().

  1. onDestroy() chamado: Vá para Configurações -> Aplicativo -> Serviços em execução -> Selecione e pare seu serviço.

  2. 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.

Paulo
fonte
7

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.

Kevin Parker
fonte
6

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.

Pieter-Jan Van Robays
fonte
3
Essa discussão ocorreu em 26/12/07. Em julho deste ano (ou seja, no futuro), ou antes do Android ser público. De qualquer maneira, isso não me faz confiar.
Tom
Essa discussão é de 26 de dezembro de 2007. Eles estão discutindo uma versão de pré-lançamento ( developer.android.com/sdk/OLD_RELEASENOTES.html#m3-rc37a ), lançada em 14 de dezembro de 2007.
ingh.am
6

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.

Snicolas
fonte
1
Combine ou atualize sua resposta anterior. Evite postar mais de uma resposta por postagem.
ChuongPham #
Esta resposta pode ser expandida, ou seja, como associar o valor do CODE ao serviço?
Dave Nottage
Onde obter contexto?
basil
6

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(...);
    }
TheRealChx101
fonte
O único problema com isso é se o serviço for um serviço fixo e for reiniciado automaticamente. Ligar para isServiceCreated () retornará false depois que o serviço for iniciado novamente, porque mInstance será nulo.
Mira_Cole
1
O onCreate não seria chamado quando o serviço fosse reiniciado?
TheRealChx101
6

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;
}
Nima
fonte
Você precisa do 'Contexto' para GetSystemService.
testando
5

Para o caso de uso fornecido aqui, podemos simplesmente usar o stopService()valor de retorno do método. Retorna truese 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 falseoutro, pois o serviço atual foi interrompido. :) Seria melhor se você desse uma olhada nisso .

Rahul Raveendran
fonte
5

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)
Oscar Emilio Perez Martinez
fonte
4

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
    }
Mohamed Saber
fonte
3

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

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
}
PA Gosai
fonte
Esta é uma ótima resposta para escrever testes, pois você pode usá-lo sem alterar seu código de trabalho.
Robert Liberatore
2

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)
Luis Eduardo Moreno
fonte
6
ActivityManager.getRunningServicesestá obsoleto desde o Android O
Daniel Shatz
1

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 loremno 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 ComponentNamecasos, 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;
}

Nome do componente

Maksim Dmitriev
fonte
1

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

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.

Joe Plante
fonte
0

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.

FranMowinckel
fonte
0

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.

Badr
fonte
4
Isso não funciona se o serviço for morto pelo Android.
Heisenberg
@Heisenberg Acabei de experimentar isso sozinho. Você sabe porque não?
Tim
@Heisenberg quando meu aplicativo é morto por OS, o serviço for reiniciado e define o bool estático para verdade, mas ao chegar ele relata falsos
Tim
isso não funcionará se você ligar stopService. Pelo menos para serviços Intent. onDestroy()será chamado imediatamente, mas onHandleIntent()ainda estará funcionando
serggl
1
@Heisenberg Não matar o serviço devido à pouca memória também significa matar o processo?
desenvolvedor android
0

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

atualização 23.06.2018

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

*

ceph3us
fonte
bindResult (valor de retorno do método bindService) não será falso se o serviço não estiver em execução.
Shangeeth Sivan
0

Minha conversão kotlin das ActivityManager::getRunningServicesrespostas 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
Gulshan
fonte
-2

É 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.
Haomin
fonte
-5

Calma galera ... :)

Eu acho que a solução mais adequada é manter um par de valores-chave SharedPreferencessobre 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.

Taner
fonte
19
Só que ninguém atualizará o valor para você quando eles matarem o serviço
Gunnar Forsgren - Mobimation
quando matar o onDestroy serviço () será disparado e que é possível atualizar seu estado
Jongz Puangput
5
@JongzPuangput, onDestroynem sempre é chamado quando o serviço é interrompido . Por exemplo, vi meus serviços serem mortos em situações de pouca memória sem onDestroyserem chamados.
Sam
@ Sam Então, como será chamado?
Ruchir Baronia
2
@RuchirBaronia Tanto quanto me lembro, você simplesmente não é notificado quando suas coisas são mortas. Acredito que o Android foi projetado para matar aplicativos, conforme necessário, e os aplicativos devem ser projetados para serem mortos a qualquer momento, sem notificação.
Sam