Estou confuso aqui .. por que o android não pode fornecer uma substituição simples na classe do aplicativo para isso? É muito difícil saber isso no nível da plataforma? @Override protegido void onApplicationSentToBackground () {}
Chuck D
2
@ ChuckD - isso faria sentido, que é o que o SDK do Android parece evitar às vezes. : /
O iOS tem esse problema, não sei por que o Google torna isso tão difícil. É uma necessidade tão óbvia.
Jerry Destremps
Respostas:
388
Existem algumas maneiras de detectar se seu aplicativo está sendo executado em segundo plano, mas apenas uma delas é totalmente confiável:
A solução certa (créditos vão para Dan , CommonsWare e NeTeInStEiN )
visibilidade da trilha de sua aplicação por si mesmo usando Activity.onPause, Activity.onResumemétodos. Armazene o status de "visibilidade" em outra classe. Boas escolhas são sua própria implementação do Applicationou a Service(também existem algumas variações dessa solução, se você quiser verificar a visibilidade da atividade do serviço).
Exemplo
Implementar Applicationclasse personalizada (observe o isActivityVisible()método estático):
Adicione onPausee onResumea todos Activityno projeto (você pode criar um ancestral comum para suas atividades, se desejar, mas se sua atividade já estiver estendida de MapActivity/ ListActivityetc., você ainda precisará escrever o seguinte manualmente):
A atualização ActivityLifecycleCallbacks foi adicionada no nível da API 14 (Android 4.0). Você pode usá-los para rastrear se uma atividade do seu aplicativo está atualmente visível para o usuário. Verifique a resposta da Cornstalks abaixo para obter detalhes.
O errado,
eu costumava sugerir a seguinte solução:
Você pode detectar atualmente o aplicativo de primeiro plano / plano de fundo com o ActivityManager.getRunningAppProcesses()qual retorna uma lista de RunningAppProcessInforegistros. Para determinar se sua aplicação é no cheque primeiro plano RunningAppProcessInfo.importancecampo de igualdade para RunningAppProcessInfo.IMPORTANCE_FOREGROUNDquando RunningAppProcessInfo.processNameé igual ao seu nome de pacote de aplicativos.
Além disso, se você ligar a ActivityManager.getRunningAppProcesses()partir do encadeamento da interface do usuário do aplicativo, ele retornará importância IMPORTANCE_FOREGROUNDà sua tarefa, independentemente de estar realmente em primeiro plano ou não. Chame-o no thread de segundo plano (por exemplo, via AsyncTask) e ele retornará os resultados corretos.
Embora essa solução possa funcionar (e de fato funciona na maioria das vezes), recomendo abster-se de usá-la. E aqui está o porquê. Como Dianne Hackborn escreveu :
Essas APIs não existem para os aplicativos basearem o fluxo da interface do usuário, mas para fazer coisas como mostrar ao usuário os aplicativos em execução, um gerenciador de tarefas ou algo assim.
Sim, há uma lista mantida na memória para essas coisas. No entanto, ele está desativado em outro processo, gerenciado por threads em execução separadamente do seu, e não é algo que você possa contar (a) vendo a tempo de tomar a decisão correta ou (b) tenha uma imagem consistente no momento em que você retornar. Além disso, a decisão sobre o que a "próxima" atividade a ser realizada é sempre feita no ponto em que a troca ocorrerá e não é até aquele ponto exato (em que o estado da atividade é bloqueado brevemente para fazer a troca) que nós realmente sei com certeza qual será a próxima coisa.
E não é garantido que a implementação e o comportamento global aqui permaneçam os mesmos no futuro.
Eu gostaria de ter lido isso antes de postar uma resposta no SO, mas espero que não seja tarde demais para admitir o meu erro.
Outra solução errada que a biblioteca Droid-Fu mencionada em uma das respostas usa ActivityManager.getRunningTaskspara seu isApplicationBroughtToBackgroundmétodo. Veja o comentário de Dianne acima e também não use esse método.
Para saber se você pressionou o botão home ou algum outro aplicativo ganhou o foco: 1) implemente a boa solução . 2) A OnStoppedido de isActivityVisible.
Brais Gabin
28
Infelizmente, sua solução 'correta' não funciona para mim. Considere percorrer as atividades em seu aplicativo. O que acontece então é que o sinalizador 'inForeground' é assim: True, False (Entre a 1ª atividade da onPause e a 2ª atividade da onResume) e depois True novamente, etc. Você precisaria de algum tipo de histerese.
Radu
14
Esta solução não funcionará se você não puder controlar diretamente todas as atividades. Por exemplo, se você tiver uma atividade de um sdk de terceiros ou mesmo iniciar uma intenção ACTION_VIEW.
precisa saber é o seguinte
66
O Android é um naufrágio. Ninguém pensou que alguém poderia querer manter os dados no nível do aplicativo? Dê uma pausa
8
Parece que a resposta real para esta pergunta é "Você não pode verificar corretamente". A chamada solução 'correta' é uma solução alternativa, na melhor das hipóteses, assim como o ActivityLifecycleCallbacks. Você ainda precisa considerar alternar entre atividades que seriam registradas como "não em primeiro plano". Ele sopra minha mente que você não pode verificar uma coisa simples como isso ...
Vou deixar minha resposta original aqui por causa da posteridade. Este foi o melhor disponível em 2012, mas agora o Android tem suporte adequado para isso.
Resposta original
A chave está em uso ActivityLifecycleCallbacks(observe que isso requer o nível 14 da API do Android (Android 4.0)). Basta verificar se o número de atividades interrompidas é igual ao número de atividades iniciadas. Se eles são iguais, seu aplicativo está em segundo plano. Se houver mais atividades iniciadas, seu aplicativo ainda estará visível. Se houver mais atividades retomadas do que pausadas, seu aplicativo não estará apenas visível, mas também em primeiro plano. Existem três estados principais em que sua atividade pode estar: visível e em primeiro plano, visível, mas não em primeiro plano, e não visível e não em primeiro plano (ou seja, em primeiro plano).
O mais interessante desse método é que ele não possui problemas assíncronos getRunningTasks(), mas você também não precisa modificar todos os Activityaplicativos para definir / desabilitar algo em onResumed()/ onPaused(). São apenas algumas linhas de código que são independentes e funcionam em todo o aplicativo. Além disso, também não há permissões funky.
MyLifecycleHandler.java:
publicclassMyLifecycleHandlerimplementsActivityLifecycleCallbacks{// I use four separate variables here. You can, of course, just use two and// increment/decrement them instead of using four and incrementing them all.privateint resumed;privateint paused;privateint started;privateint stopped;@Overridepublicvoid onActivityCreated(Activity activity,Bundle savedInstanceState){}@Overridepublicvoid onActivityDestroyed(Activity activity){}@Overridepublicvoid onActivityResumed(Activity activity){++resumed;}@Overridepublicvoid onActivityPaused(Activity activity){++paused;
android.util.Log.w("test","application is in foreground: "+(resumed > paused));}@Overridepublicvoid onActivitySaveInstanceState(Activity activity,Bundle outState){}@Overridepublicvoid onActivityStarted(Activity activity){++started;}@Overridepublicvoid onActivityStopped(Activity activity){++stopped;
android.util.Log.w("test","application is visible: "+(started > stopped));}// If you want a static function you can use to check if your application is// foreground/background, you can use the following:/*
// Replace the four variables above with these four
private static int resumed;
private static int paused;
private static int started;
private static int stopped;
// And these two public static functions
public static boolean isApplicationVisible() {
return started > stopped;
}
public static boolean isApplicationInForeground() {
return resumed > paused;
}
*/}
MyApplication.java:
// Don't forget to add it to your manifest by doing// <application android:name="your.package.MyApplication" ...publicclassMyApplicationextendsApplication{@Overridepublicvoid onCreate(){// Simply add the handler, and that's it! No need to add any code// to every activity. Everything is contained in MyLifecycleHandler// with just a few lines of code. Now *that's* nice.
registerActivityLifecycleCallbacks(newMyLifecycleHandler());}}
O @Mewzer fez algumas boas perguntas sobre esse método que eu gostaria de responder nesta resposta para todos:
onStop()não é chamado em situações de pouca memória; isso é um problema aqui?
Não. Os documentos para onStop()dizer:
Observe que esse método nunca pode ser chamado, em situações de pouca memória em que o sistema não possui memória suficiente para manter o processo de sua atividade em execução após a chamada do método onPause ().
A chave aqui é "manter o processo de sua atividade em execução ..." Se essa situação de pouca memória for atingida, seu processo será realmente eliminado (não apenas sua atividade). Isso significa que esse método de verificação do background-ness ainda é válido porque a) você não pode verificar o background de qualquer maneira se o processo for interrompido eb) se o processo iniciar novamente (porque uma nova atividade é criada), o membro variáveis (estáticas ou não) para MyLifecycleHandlerserão redefinidas para0 .
Isso funciona para alterações na configuração?
Por padrão, não. Você deve definir explicitamente configChanges=orientation|screensize( |com qualquer outra coisa que desejar) em seu arquivo de manifesto e manipular as alterações na configuração, caso contrário, sua atividade será destruída e recriada. Se você não definir isso, os métodos de sua atividade será chamado nesta ordem: onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume. Como você pode ver, não há sobreposição (normalmente, duas atividades se sobrepõem muito rapidamente ao alternar entre as duas, e é assim que esse método de detecção de plano de fundo funciona). Para contornar isso, você deve definir configChangespara que sua atividade não seja destruída. Felizmente, eu tive que definirconfigChangesjá em todos os meus projetos, porque não era desejável que toda a minha atividade fosse destruída na tela girar / redimensionar, então nunca achei isso problemático. (obrigado a dpimka por refrescar minha memória e me corrigir!)
Uma nota:
Quando eu disse "plano de fundo" aqui nesta resposta, quis dizer "seu aplicativo não está mais visível". As atividades do Android podem estar visíveis, mas não em primeiro plano (por exemplo, se houver uma sobreposição de notificação transparente). É por isso que atualizei esta resposta para refletir isso.
É importante saber que o Android tem um momento estranho de limbo ao alternar atividades onde nada está em primeiro plano . Por esse motivo, se você verificar se seu aplicativo está em primeiro plano ao alternar entre atividades (no mesmo aplicativo), você será informado de que não está em primeiro plano (mesmo que seu aplicativo ainda seja o aplicativo ativo e esteja visível )
Você pode verificar se seu aplicativo estiver em primeiro plano em sua Activity's onPause()método depoissuper.onPause() . Lembre-se do estranho estado do limbo que acabei de falar.
Você pode verificar se seu aplicativo é visível (ou seja, se ele não está no fundo) em sua Activity's onStop()método depoissuper.onStop() .
Isso parece interessante - mas o que acontece em situações de pouca memória? Não é garantido que onStop () seja chamado. Poderíamos entrar na situação em que um onStop () não é chamado e o contador parado não é incrementado - isso significa que a verificação em segundo plano não é mais confiável? Ou isso nunca aconteceria?
Mewzer
1
Além disso, isso ignorará as alterações na configuração? Ou o aplicativo será considerado em segundo plano se uma atividade for recriada como resultado de uma alteração na configuração (por exemplo, mudança na orientação) ?. Desculpe, pelas perguntas, mas acho que você gosta de algo e está interessado em saber se funciona nesses casos extremos.
Mewzer
1
@Mewzer: Eu ia responder como um comentário, mas será necessário digitar um pouco para obter essas respostas, então volte em alguns minutos e eu editarei minha resposta.
Cornstalks
1
@ Mrzer: Você deve encontrar suas respostas agora. Deixe-me saber se existem outras perguntas!
Cornstalks
2
@Mewzer: Acabei de adicionar uma observação que lhe interessa. Especificamente, verifique se há antecedentes onStop()depois super.onStop(). Não verifique se há antecedentes onPause().
precisa
187
SOLUÇÃO DO GOOGLE - não um truque, como as soluções anteriores. Use ProcessLifecycleOwner
Kotlin:
classArchLifecycleApp:Application(),LifecycleObserver{override fun onCreate(){super.onCreate()ProcessLifecycleOwner.get().lifecycle.addObserver(this)}@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded(){//App in background}@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onAppForegrounded(){// App in foreground}}
Java:
publicclassArchLifecycleAppextendsApplicationimplementsLifecycleObserver{@Overridepublicvoid onCreate(){super.onCreate();ProcessLifecycleOwner.get().getLifecycle().addObserver(this);}@OnLifecycleEvent(Lifecycle.Event.ON_STOP)publicvoid onAppBackgrounded(){//App in background}@OnLifecycleEvent(Lifecycle.Event.ON_START)publicvoid onAppForegrounded(){// App in foreground}}
no app.gradle
dependencies {...
implementation "android.arch.lifecycle:extensions:1.1.0"//New Android X dependency is this -
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"}
allprojects {
repositories {...
google()
jcenter()
maven { url 'https://maven.google.com'}}}
Definitivamente, essa deve ser a resposta correta! Funcionou como um encanto: D
JaviOverflow
2
Isso funciona perfeitamente, eu também modifiquei um pouco para poder acessar o estado de primeiro plano / plano de fundo mais facilmente fora desta classe: companion object { private var foreground = false fun isForeground() : Boolean { return foreground } }então você pode obter o estado de primeiro plano com #ArchLifecycleApp.isForeground()
Jose Jose
2
Oh cara, isso é muito melhor do que minha resposta antiga. Tenha um +1 de mim. Atualizei minha resposta para apontar as pessoas para a sua.
Cornstalks
2
Embora seja uma resposta correta, não há necessidade de implementar retornos de chamada, você pode consultar o ProcessLifecycleOwner sempre que quiser. Verifique stackoverflow.com/a/52678290/6600000
Keivan Esbati
2
Como o doc diz The LifecycleOwner for the whole application process. Note that if your application has multiple processes, this provider does not know about other processes. , isso não está funcionando para multiple processesaplicativos. Existe alguma API que podemos alcançar com elegância?
acntwww
23
Iniciando a biblioteca de suporte versão 26, você pode usar ProcessLifecycleOwner , basta adicioná-lo à sua dependência, como descrito aqui , por exemplo:
dependencies {def lifecycle_version ="1.1.1"// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:$lifecycle_version"// alternatively - Lifecycles only (no ViewModel or LiveData).// Support library depends on this lightweight import
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"// use kapt for Kotlin}
E, em seguida, basta consultar ProcessLifecycleOwnersempre que desejar o estado do aplicativo, exemplos:
//Check if app is in backgroundProcessLifecycleOwner.get().getLifecycle().getCurrentState()==Lifecycle.State.CREATED;//Check if app is in foregroundProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);
Obrigado cara, esta é a melhor e mais fácil maneira que é adequada em qualquer parte do seu código, especialmente ao usar o fcm.
Mihae Kheel
se o aplicativo for fechado completamente, o que o primeiro método retornaria?
Evgeniy Mishustin 04/07/19
@EvgeniyMishustin que depende do estado atual do aplicativo, mas geralmente você vê CREATED, DESTROYED e depois disso, você não recebe novos eventos.
Keivan Esbati 04/04/19
Então, onde está qualquer declaração "SE" para ver se o aplicativo está em segundo plano (primeiro plano) ???
ekashking
@ekashking apenas coloca a declaração inteira na cláusula if. Por exemplo: if (ProcessLifecycleOwner.get (). GetLifecycle (). GetCurrentState (). IsAtLeast (Lifecycle.State.STARTED)) => O aplicativo está em primeiro plano
Keivan Esbati
20
Desde a API do Android 16, existe uma maneira simples de verificar se o aplicativo está em primeiro plano. Pode não ser infalível, mas nenhum método no Android é infalível. Esse método é bom o suficiente para usar quando seu serviço recebe atualização do servidor e precisa decidir se deseja mostrar uma notificação ou não (porque se a interface do usuário estiver em primeiro plano, o usuário notará a atualização sem notificação).
esse código deve estar dentro da classe Service ou outra classe, por exemplo, classe Application? Muito obrigado.
Woppi
..quando você quiser usá-lo, como a linha final é apenas um booleano contra o qual você verificaria.
AO_
Essa é a mesma metodologia do AWS Android SDK para notificações por push.
Spakmad
Esteja ciente de que "A definição de plano de fundo para fins de limitações de serviço é distinta da definição usada pelo gerenciamento de memória; um aplicativo pode estar em segundo plano no que diz respeito ao gerenciamento de memória, mas em primeiro plano no que diz respeito à sua capacidade de iniciar serviços.) " developer.android.com/about/versions/oreo/background.html (
ARLabs
Obrigado, isso funcionou! Consegui usar esse código em um JobServicepara detectar que o serviço está sendo executado em segundo plano.
Idolon's answer is error prone- infelizmente tenho que concordar com você. Com base no comentário de Dianne Hackborn nos Grupos do Google, atualizei minha resposta. Verifique-o por favor para os detalhes.
Idolon 8/08
2
Esta também não é uma solução infalível. Um cenário é se o usuário puxado para baixo o painel de notificação, em seguida, nem o onPause, onStopnem o onResumeevento é chamado. Então, o que você faz se nenhum desses eventos for acionado ?!
Infelizmente, mas esse código funciona errado quando uma atividade é iniciada quando uma tela está desligada. Nesse caso, onResume e onPause são chamados tornando isVisible = false.
CoolMind 10/05
@CoolMind Você pode explicar qual é o caso de uso em que você iniciaria uma atividade em segundo plano?
Neteinstein 10/05
11
Tentei a solução recomendada que usa Application.ActivityLifecycleCallbacks e muitos outros, mas eles não funcionaram conforme o esperado. Graças ao Sarge , eu vim com uma solução bastante fácil e direta que estou descrevendo abaixo.
A chave da solução é o fato de entendermos que, se tivermos ActivityA e ActivityB, e chamarmos ActivityB de ActivityA (e não chamar ActivityA.finish), os ActivityB onStart()serão chamados antes de ActivityA onStop().
Essa também é a principal diferença entre onStop()e onPause()que nenhuma mencionou nos artigos que li.
Portanto, com base no comportamento do ciclo de vida dessa atividade, você pode simplesmente contar quantas vezes foi onStart()e onPause()foi chamado em seu programa. Observe que para cadaActivity programa, você deve substituir onStart()e onStop(), a fim de aumentar / diminuir a variável estática usada para a contagem. Abaixo está o código que implementa essa lógica. Observe que estou usando uma classe que se estende Application; portanto, não se esqueça de declarar emManifest.xml dentro da tag Application:, android:name=".Utilities"embora possa ser implementada usando uma classe personalizada simples também.
publicclassUtilitiesextendsApplication{privatestaticint stateCounter;publicvoid onCreate(){super.onCreate();
stateCounter =0;}/**
* @return true if application is on background
* */publicstaticboolean isApplicationOnBackground(){return stateCounter ==0;}//to be called on each Activity onStart()publicstaticvoid activityStarted(){
stateCounter++;}//to be called on each Activity onStop()publicstaticvoid activityStopped(){
stateCounter--;}}
Agora, em cada Atividade do nosso programa, devemos substituir onStart()eonStop() e aumentar / diminuir conforme mostrado abaixo:
@Overridepublicvoid onStart(){super.onStart();Utilities.activityStarted();}@Overridepublicvoid onStop(){Utilities.activityStopped();if(Utilities.isApplicationOnBackground()){//you should want to check here if your application is on background}super.onStop();}
Com essa lógica, existem 2 casos possíveis:
stateCounter = 0 : O número de paradas é igual ao número de atividades iniciadas, o que significa que o aplicativo está sendo executado em segundo plano.
stateCounter > 0 : O número de iniciados é maior que o número de interrompidos, o que significa que o aplicativo está sendo executado em primeiro plano.
Aviso prévio: stateCounter < 0 significaria que há mais atividades interrompidas do que iniciadas, o que é impossível. Se você encontrar esse caso, significa que não está aumentando / diminuindo o contador como deveria.
Você está pronto para ir. Você deve verificar se seu aplicativo está em segundo plano por dentro onStop().
Eu me mudaria if(Utilities.isApplicationOnBackground()) …para Utilities. Porque, caso contrário, apenas uma atividade específica reagirá ao evento.
Nome de exibição
10
A menos que você mesmo o rastreie, não há como determinar se alguma de suas atividades é visível ou não. Talvez você deva pensar em fazer uma nova pergunta no StackOverflow, explicando o que você está tentando obter com a experiência do usuário, para que possamos fornecer idéias alternativas de implementação.
No android, temos uma configuração chamada "Dados em segundo plano". Essa configuração ativa qualquer conexão de dados em segundo plano quando o aplicativo está sendo executado em segundo plano. Desejo implementar a alternância "Dados em segundo plano" para meu aplicativo. Portanto, quando nenhuma de minhas atividades estiver visível para o usuário, gostaria que meu serviço parasse de fazer qualquer transferência de dados, mas, no momento em que uma de minhas atividades for retomada, gostaria de retomar a transferência de dados
cppdev 08/09
1
@cppdev: Felizmente, a "transferência de dados" está sendo conduzida por um Service. Nesse caso, faça com que suas atividades notifiquem o serviço à medida que aparecerem e desaparecerem. Se Servicedeterminar que não há atividades visíveis e permanecer assim por algum tempo, pare a transferência de dados no próximo ponto de parada lógica. Sim, isso exigirá código para cada uma de suas atividades, mas, no momento, isso é inevitável para o AFAIK.
CommonsWare
1
Se você deseja evitar copiar e colar o código comum entre todas as suas atividades, é possível criar uma classe que MyActivityClassherda Activitye implementa os métodos do ciclo de vida e fazer com que todas as suas atividades sejam herdadas MyActivityClass. Este, sem trabalho para PreferenceActivityou MapActivityembora (ver esta questão )
Guillaume Brunerie
@CommonsWare eu tinha tentado com OnPause () onResume () que é ativo ou não, mas se meu aplicativo vista dosen't na tela de visualização se ele é executado em segundo plano como verificar se ele está ativo ou não
Manoj
@CommonsWare eu tinha tentado com OnPause () onResume () que é ativo ou não, mas se meu aplicativo vista dosen't na tela de visualização se ele é executado em segundo plano como verificar se ele está ativo ou não
Manoj
5
Você pode usar o ComponentCallbacks2 para detectar se o aplicativo está em segundo plano. BTW este retorno de chamada está disponível apenas na API Nível 14 (Ice Cream Sandwich) e acima.
Você receberá uma chamada para o método:
public abstract void onTrimMemory (int level)
se o nível é ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN , o aplicativo estará em segundo plano.
Você pode implementar essa interface para um activity, serviceetc.
publicclassMainActivityextendsAppCompatActivityimplementsComponentCallbacks2{@Overridepublicvoid onConfigurationChanged(finalConfiguration newConfig){}@Overridepublicvoid onLowMemory(){}@Overridepublicvoid onTrimMemory(finalint level){if(level ==ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN){// app is in background}}}
Tentei sua resposta, mas não é tão confiável. o retorno de chamada onTrimMemory não será acionado quando a tela estiver bloqueada nem ao pressionar o botão "ligar / desligar" para bloquear a tela. Também nem sempre retornará TRIM_MEMORY_UI_HIDDEN se seu aplicativo estiver visível e você abrir outro aplicativo por meio de uma notificação da barra de status. A única solução confiável é implementar os ActivityLifecycleCallbacks e ajustá-los aos casos de uso.
velval
4
Com base no @Cornstalks, responda para incluir alguns recursos úteis.
Recursos extras:
introduziu o padrão singleton para que você possa fazer isso em qualquer lugar do aplicativo: AppLifecycleHandler.isApplicationVisible () e AppLifecycleHandler.isApplicationInForeground ()
manipulação adicional de eventos duplicados (consulte os comentários // execute alguma ação sobre alteração de visibilidade e // execute alguma ação sobre alteração de primeiro plano)
Você iniciou um timer em onPause () e cancelou o mesmo timer em onResume (); há 1 instância do Timer (geralmente definida na classe Application). O cronômetro propriamente dito está definido para executar um Runnable após 2 segundos (ou qualquer intervalo que você julgar apropriado), quando o cronômetro é acionado, você define um sinalizador que marca o aplicativo como em segundo plano.
No método onResume () antes de cancelar o timer, você pode consultar o sinalizador em segundo plano para executar qualquer operação de inicialização (por exemplo, iniciar downloads ou ativar os serviços de localização).
Esta solução permite que você tenha várias atividades na pilha de trás e não requer nenhuma permissão para implementar.
Essa solução funciona bem se você também usar um barramento de eventos, pois o timer pode simplesmente disparar um evento e várias partes do seu aplicativo podem responder de acordo.
Eu estou começando a pensar que este é o melhor (embora infeliz) solução
dhaag23
Sim, esta é a melhor solução que eu também consegui. Eu precisava interromper a verificação do bluetooth quando o aplicativo não estava em primeiro plano, mas não podia simplesmente usar a pausa, parar ou destruir, porque não queria parar e iniciar constantemente quando o usuário navegava pelo aplicativo.
CaptRespect
3
Se você ativar as configurações do desenvolvedor "Não mantenha atividades" - verifique se apenas a contagem de atividades criadas não é suficiente. Você também deve verificar isSaveInstanceState . Minha verificação personalizada do método isApplicationRunning () está executando o aplicativo Android:
Não vejo como essa solução pode me dar uma resposta sobre uma pergunta simples em uma declaração IF sobre minha atividade (ou fragmento), se meu aplicativo está em segundo plano ou em primeiro plano. Onde está a instrução "SE" ???
ekashking
2
Para pegar o que o CommonsWare e Key disseram, talvez você possa estender a classe Application e fazer com que todas as suas atividades chamem isso pelos métodos onPause / onResume. Isso permitiria que você soubesse quais atividades estão visíveis, mas isso provavelmente poderia ser tratado melhor.
Você pode elaborar exatamente o que tem em mente? Quando você diz que está executando em segundo plano, quer dizer simplesmente manter seu aplicativo na memória, mesmo que ele não esteja atualmente na tela? Você já pensou em usar os Serviços como uma maneira mais persistente de gerenciar seu aplicativo quando ele não está em foco?
No android, temos uma configuração chamada "Dados em segundo plano". Essa configuração ativa qualquer conexão de dados em segundo plano quando o aplicativo está sendo executado em segundo plano. Desejo implementar a alternância "Dados em segundo plano" para meu aplicativo. Portanto, quando nenhuma de minhas atividades estiver visível para o usuário, gostaria que meu serviço parasse de fazer qualquer transferência de dados, mas, no momento em que uma de minhas atividades for retomada, gostaria de retomar a transferência de dados
cppdev 08/09
1
Applicationnão tem onPause()ou onResume().
CommonsWare
1
@CommonsWare Você está certo, eu estava me referindo a cada atividade individual que entra em contato com o aplicativo em sua pausa / resumo. Essa é basicamente a idéia que você acabou de compartilhar no comentário à sua resposta, embora tenha usado os Serviços que, imagino, são uma jogada mais inteligente.
Dan
2
Fiz minha própria implementação do ActivityLifecycleCallbacks. Estou usando SherlockActivity, mas para a classe Activity normal pode funcionar.
Primeiro, estou criando uma interface que possui todos os métodos para rastrear o ciclo de vida das atividades:
A atividade é pausada quando um diálogo fica acima dele, portanto todas as soluções recomendadas são meias soluções. Você precisa criar ganchos para diálogos também.
O sistema distingue entre aplicativos em primeiro plano e em segundo plano. (A definição de plano de fundo para fins de limitações de serviço é distinta da definição usada pelo gerenciamento de memória; um aplicativo pode estar em segundo plano no que diz respeito ao gerenciamento de memória , mas em primeiro plano no que diz respeito à sua capacidade de iniciar serviços.) considerado em primeiro plano se alguma das seguintes situações for verdadeira:
Tem uma atividade visível, seja a atividade iniciada ou pausada.
Tem um serviço em primeiro plano.
Outro aplicativo em primeiro plano está conectado ao aplicativo, vinculando-se a um de seus serviços ou utilizando um de seus provedores de conteúdo. Por exemplo, o aplicativo está em primeiro plano se outro aplicativo se vincular a:
IME
Serviço de papel de parede
Ouvinte de notificação
Serviço de voz ou texto
Se nenhuma dessas condições for verdadeira, o aplicativo será considerado em segundo plano.
Você deve usar uma preferência compartilhada para armazenar a propriedade e agir de acordo com ela usando a ligação de serviço de suas atividades. Se você usar apenas a ligação (que nunca usa startService), seu serviço será executado apenas quando você se vincular a ele (bind onResume e unbind onPause) que o executaria apenas em primeiro plano e se desejar trabalhar em Em segundo plano, você pode usar o serviço de parada de partida regular.
Eu acho que essa pergunta deveria ser mais clara. Quando? Onde? Qual é a sua situação específica que você deseja saber se o aplicativo estiver em segundo plano?
Acabei de apresentar minha solução do meu jeito.
Consigo fazer isso usando o campo "importância" da RunningAppProcessInfoclasse no onStopmétodo de todas as atividades do meu aplicativo, o que pode ser alcançado simplesmente fornecendo uma BaseActivityextensão para outras atividades que implementam o onStopmétodo para verificar o valor de "importância". Aqui está o código:
Eu tenho cerca de 10 atividades no meu aplicativo. Então, eu quero saber se nenhum deles está visível para o usuário. Em todos, eu quero saber se meu aplicativo como um todo está sendo executado em segundo plano
cppdev
Então, você acompanha todos os 10-ish. Ou, como o CommonsWare sugeriu, explique o que você está tentando fazer.
Key
3
Isto não está correto. Sua atividade é visível até onStop; entre onPausee onStopé visível , mas não em primeiro plano .
nickgrim
@ Rickgrim: o que não está correto? Afirmei que uma atividade não é mais visível depois que onStop()é chamada, alinhada com o que você escreveu.
Key
@ Key: Você disse originalmente até onPauseé chamado: uma edição recente o corrigiu.
nickgrim 20/05
0
Que tal usar getApplicationState (). IsInForeground ()?
Na minha opinião, muitas respostas introduzem uma carga pesada de código e traz muita complexidade e falta de legibilidade.
Quando as pessoas perguntam sobre como se comunicar entre a Servicee a Activity, geralmente aconselho usar o LocalBroadcastManager .
Por quê?
Bem, citando os documentos:
Você sabe que os dados que você está transmitindo não sairão do aplicativo, portanto, não se preocupe com o vazamento de dados particulares.
Não é possível que outros aplicativos enviem essas difusões para seu aplicativo, portanto, você não precisa se preocupar em ter falhas de segurança que eles possam explorar.
É mais eficiente do que enviar uma transmissão global através do sistema.
Não está nos documentos:
Não requer bibliotecas externas
O código é mínimo
É rápido de implementar e entender
Nenhum retorno de chamada personalizado auto-implementado / ultra-singleton / padrão intra-processo, qualquer que seja ...
Há fortes referências sobre Activity, Application...
Descrição
Portanto, você deseja verificar se algum dos itens Activityestá atualmente em primeiro plano. Você costuma fazer isso em uma aula Serviceou na sua Applicationclasse.
Isso significa que seus Activityobjetos se tornam o remetente de um sinal (estou ligado / desligado). Seu Service, por outro lado, se torna o Receiver.
Existem dois momentos em que seuActivity você diz se está indo em primeiro plano ou em segundo plano (sim, apenas dois ... não 6).
Quando Activityentra em primeiro plano, o onResume()método é acionado (também chamado apósonCreate() ).
Quando Activityvai pelas costas,onPause() é chamado.
Estes são os momentos em que você Activitydeve enviar o sinal para o seuService para descrever seu estado.
No caso de múltiplos Activity, lembre-se doActivity se de que o primeiro entra em segundo plano e depois outro entra em primeiro plano.
O Service/ Applicationcontinuará ouvindo esses sinais e agirá de acordo.
Código (TLDR)
Você Servicedeve implementar um BroadcastReceiverpara ouvir sinais.
this.localBroadcastReceiver =newBroadcastReceiver(){@Overridepublicvoid onReceive(Context context,Intent intent){// received data if Activity is on / off}}publicstaticfinalIntentFilter SIGNAL_FILTER =newIntentFilter("com.you.yourapp.MY_SIGNAL")
@Overrideprotectedvoid onDestroy(){// I'm dead, no need to listen to anything anymore.LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);}
Agora o seu Activitydeve comunicar o estado deles.
No Activity::onResume()
Intent intent =newIntent();
intent.setAction(SomeActivity.SIGNAL_FILTER);// put ON boolean in intent LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
No Activity::onPause()
Intent intent =newIntent();
intent.setAction(SomeActivity.SIGNAL_FILTER);// put OFF boolean in intent LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
Uma situação muito, muito comum
Desenvolvedor: desejo enviar dados meus Servicee atualizar o Activity. Como verifico se o Activityestá em primeiro plano?
Geralmente, não é necessário verificar se Activityo item está em primeiro plano ou não. Basta enviar os dados via LocalBroadcastManagerdo seu Service. Se Activityestiver ativado, ele responderá e agirá.
Para esta situação muito comum, o Servicetorna-se o remetente e o Activityimplementa o BroadcastReceiver.
Então, crie um Receiverno seu Activity. Registre-o onResume()e cancele o registro onPause(). Não há necessidade de usar os outros métodos de ciclo de vida .
Defina o Receivercomportamento em onReceive()(atualize o ListView, faça isso, faça aquilo, ...).
Dessa forma, o Activityouvirá apenas se estiver em primeiro plano e nada acontecerá se estiver nas costas ou for destruído.
No caso de múltiplos Activity, o que Activityestiver ativado responderá (se eles também implementarem o Receiver).
Se tudo estiver em segundo plano, ninguém responderá e o sinal simplesmente se perderá.
Envie os dados da Servicevia Intent(consulte o código acima) especificando o ID do sinal.
Exceto pelo suporte para várias janelas . Pode ser complicado (por favor, teste-o se necessário) ...
fun isAppInForeground():Boolean{
val activityManager = getSystemService(Context.ACTIVITY_SERVICE)asActivityManager?:returnfalse
val appProcesses = activityManager.runningAppProcesses ?:returnfalse
val packageName = packageName
for(appProcess in appProcesses){if(appProcess.importance ==ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName == packageName){returntrue}}returnfalse}
Nenhuma das respostas se encaixava perfeitamente no caso específico se você procurasse saber se uma atividade específica está em andamento e se você é um SDK sem acesso direto ao Aplicativo. Para mim, eu estava no segmento de segundo plano, tendo recebido apenas uma notificação por push para uma nova mensagem de bate-papo e só quero exibir uma notificação do sistema se a tela de bate-papo não estiver em primeiro plano.
Usando o ActivityLifecycleCallbacksque foi recomendado em outras respostas, criei uma pequena classe util que abriga a lógica para MyActivityestar ou não em primeiro plano.
classMyActivityMonitor(context:Context):Application.ActivityLifecycleCallbacks{privatevar isMyActivityInForeground =false
init {(context.applicationContext asApplication).registerActivityLifecycleCallbacks(this)}
fun isMyActivityForeground()= isMyActivityInForeground
override fun onActivityPaused(activity:Activity?){if(activity isMyActivity){
isMyActivityInForeground =false}}override fun onActivityResumed(activity:Activity?){if(activity isMyActivity){
isMyActivityInForeground =true}}
// Show a Toast Notification if App is not visible (ie in background. Not running, etc) SharedPreferences sharedPrefs =PreferenceManager.getDefaultSharedPreferences(context);if(!sharedPrefs.getBoolean("visible",true)){...}
Talvez não seja elegante, mas funciona para mim ...
Talvez seja tarde demais para responder, mas se alguém vier visitar, aqui está a solução que eu sugiro: o (s) motivo (s) pelo qual um aplicativo deseja saber que está em segundo plano ou que está em primeiro plano pode ser muitos, alguns são 1. Para mostrar brindes e notificações quando o usuário estiver no BG. 2.Para executar algumas tarefas pela primeira vez, o usuário vem do BG, como uma enquete, redesenho etc.
A solução de Idolon e outros cuida da primeira parte, mas não da segunda. Se houver várias atividades no seu aplicativo e o usuário estiver alternando entre elas, quando você estiver na segunda atividade, o sinalizador visível será falso. Portanto, não pode ser usado deterministicamente.
Fiz algo que foi sugerido pelo CommonsWare: "Se o Serviço determinar que não há atividades visíveis e permanecer assim por algum tempo , pare a transferência de dados no próximo ponto de parada lógica".
A linha em negrito é importante e isso pode ser usado para alcançar o segundo item. Portanto, o que eu faço é quando obtenho o onActivityPaused (), não altere o visible para false diretamente, em vez disso, tenho um temporizador de 3 segundos (é o máximo que a próxima atividade deve ser iniciada) e, se não houver onActivityResumed ( ) nos próximos 3 segundos, mude de visível para falso. Da mesma forma em onActivityResumed () se houver um timer, eu o cancelo. Para resumir, o visível se torna isAppInBackground.
Desculpe, não é possível copiar e colar o código ...
Eu gostaria de recomendar que você use outra maneira de fazer isso.
Eu acho que você deseja mostrar a tela de inicialização enquanto o programa está sendo iniciado, se já estiver sendo executado no back-end, não o mostre.
Seu aplicativo pode gravar continuamente a hora atual em um arquivo específico. Enquanto o aplicativo está sendo iniciado, verifique o último registro de data e hora, se current_time-last_time> o período especificado para a gravação do horário mais recente, significa que o aplicativo foi parado, interrompido pelo sistema ou pelo próprio usuário.
Respostas:
Existem algumas maneiras de detectar se seu aplicativo está sendo executado em segundo plano, mas apenas uma delas é totalmente confiável:
A solução certa (créditos vão para Dan , CommonsWare e NeTeInStEiN )
visibilidade da trilha de sua aplicação por si mesmo usando
Activity.onPause
,Activity.onResume
métodos. Armazene o status de "visibilidade" em outra classe. Boas escolhas são sua própria implementação doApplication
ou aService
(também existem algumas variações dessa solução, se você quiser verificar a visibilidade da atividade do serviço).Exemplo
Implementar
Application
classe personalizada (observe oisActivityVisible()
método estático):Registre sua classe de aplicativo em
AndroidManifest.xml
:Adicione
onPause
eonResume
a todosActivity
no projeto (você pode criar um ancestral comum para suas atividades, se desejar, mas se sua atividade já estiver estendida deMapActivity
/ListActivity
etc., você ainda precisará escrever o seguinte manualmente):A atualização
ActivityLifecycleCallbacks foi adicionada no nível da API 14 (Android 4.0). Você pode usá-los para rastrear se uma atividade do seu aplicativo está atualmente visível para o usuário. Verifique a resposta da Cornstalks abaixo para obter detalhes.
O errado,
eu costumava sugerir a seguinte solução:
Embora essa solução possa funcionar (e de fato funciona na maioria das vezes), recomendo abster-se de usá-la. E aqui está o porquê. Como Dianne Hackborn escreveu :
Eu gostaria de ter lido isso antes de postar uma resposta no SO, mas espero que não seja tarde demais para admitir o meu erro.
Outra solução errada que
a biblioteca Droid-Fu mencionada em uma das respostas usa
ActivityManager.getRunningTasks
para seuisApplicationBroughtToBackground
método. Veja o comentário de Dianne acima e também não use esse método.fonte
OnStop
pedido deisActivityVisible
.NÃO USE ESTA RESPOSTA
A resposta do usuário1269737 é a maneira correta (aprovada pelo Google / Android) de fazer isso . Leia a resposta e dê um +1.
Vou deixar minha resposta original aqui por causa da posteridade. Este foi o melhor disponível em 2012, mas agora o Android tem suporte adequado para isso.
Resposta original
A chave está em uso
ActivityLifecycleCallbacks
(observe que isso requer o nível 14 da API do Android (Android 4.0)). Basta verificar se o número de atividades interrompidas é igual ao número de atividades iniciadas. Se eles são iguais, seu aplicativo está em segundo plano. Se houver mais atividades iniciadas, seu aplicativo ainda estará visível. Se houver mais atividades retomadas do que pausadas, seu aplicativo não estará apenas visível, mas também em primeiro plano. Existem três estados principais em que sua atividade pode estar: visível e em primeiro plano, visível, mas não em primeiro plano, e não visível e não em primeiro plano (ou seja, em primeiro plano).O mais interessante desse método é que ele não possui problemas assíncronos
getRunningTasks()
, mas você também não precisa modificar todos osActivity
aplicativos para definir / desabilitar algo emonResumed()
/onPaused()
. São apenas algumas linhas de código que são independentes e funcionam em todo o aplicativo. Além disso, também não há permissões funky.MyLifecycleHandler.java:
MyApplication.java:
O @Mewzer fez algumas boas perguntas sobre esse método que eu gostaria de responder nesta resposta para todos:
onStop()
não é chamado em situações de pouca memória; isso é um problema aqui?Não. Os documentos para
onStop()
dizer:A chave aqui é "manter o processo de sua atividade em execução ..." Se essa situação de pouca memória for atingida, seu processo será realmente eliminado (não apenas sua atividade). Isso significa que esse método de verificação do background-ness ainda é válido porque a) você não pode verificar o background de qualquer maneira se o processo for interrompido eb) se o processo iniciar novamente (porque uma nova atividade é criada), o membro variáveis (estáticas ou não) para
MyLifecycleHandler
serão redefinidas para0
.Isso funciona para alterações na configuração?
Por padrão, não. Você deve definir explicitamente
configChanges=orientation|screensize
(|
com qualquer outra coisa que desejar) em seu arquivo de manifesto e manipular as alterações na configuração, caso contrário, sua atividade será destruída e recriada. Se você não definir isso, os métodos de sua atividade será chamado nesta ordem:onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume
. Como você pode ver, não há sobreposição (normalmente, duas atividades se sobrepõem muito rapidamente ao alternar entre as duas, e é assim que esse método de detecção de plano de fundo funciona). Para contornar isso, você deve definirconfigChanges
para que sua atividade não seja destruída. Felizmente, eu tive que definirconfigChanges
já em todos os meus projetos, porque não era desejável que toda a minha atividade fosse destruída na tela girar / redimensionar, então nunca achei isso problemático. (obrigado a dpimka por refrescar minha memória e me corrigir!)Uma nota:
Quando eu disse "plano de fundo" aqui nesta resposta, quis dizer "seu aplicativo não está mais visível". As atividades do Android podem estar visíveis, mas não em primeiro plano (por exemplo, se houver uma sobreposição de notificação transparente). É por isso que atualizei esta resposta para refletir isso.
É importante saber que o Android tem um momento estranho de limbo ao alternar atividades onde nada está em primeiro plano . Por esse motivo, se você verificar se seu aplicativo está em primeiro plano ao alternar entre atividades (no mesmo aplicativo), você será informado de que não está em primeiro plano (mesmo que seu aplicativo ainda seja o aplicativo ativo e esteja visível )
Você pode verificar se seu aplicativo estiver em primeiro plano em sua
Activity
'sonPause()
método depoissuper.onPause()
. Lembre-se do estranho estado do limbo que acabei de falar.Você pode verificar se seu aplicativo é visível (ou seja, se ele não está no fundo) em sua
Activity
'sonStop()
método depoissuper.onStop()
.fonte
onStop()
depoissuper.onStop()
. Não verifique se há antecedentesonPause()
.SOLUÇÃO DO GOOGLE - não um truque, como as soluções anteriores. Use ProcessLifecycleOwner
Kotlin:
Java:
no app.gradle
Você pode ler mais sobre os componentes da arquitetura relacionados ao Ciclo de vida aqui - https://developer.android.com/topic/libraries/architecture/lifecycle
fonte
companion object { private var foreground = false fun isForeground() : Boolean { return foreground } }
então você pode obter o estado de primeiro plano com #ArchLifecycleApp.isForeground()
The LifecycleOwner for the whole application process. Note that if your application has multiple processes, this provider does not know about other processes.
, isso não está funcionando paramultiple processes
aplicativos. Existe alguma API que podemos alcançar com elegância?Iniciando a biblioteca de suporte versão 26, você pode usar ProcessLifecycleOwner , basta adicioná-lo à sua dependência, como descrito aqui , por exemplo:
E, em seguida, basta consultar
ProcessLifecycleOwner
sempre que desejar o estado do aplicativo, exemplos:fonte
Desde a API do Android 16, existe uma maneira simples de verificar se o aplicativo está em primeiro plano. Pode não ser infalível, mas nenhum método no Android é infalível. Esse método é bom o suficiente para usar quando seu serviço recebe atualização do servidor e precisa decidir se deseja mostrar uma notificação ou não (porque se a interface do usuário estiver em primeiro plano, o usuário notará a atualização sem notificação).
fonte
JobService
para detectar que o serviço está sendo executado em segundo plano.A resposta do ídolo é propensa a erros e muito mais complicada, apesar de repetida aqui. Verifique se o aplicativo Android está em primeiro plano ou não? e aqui Determinando o aplicativo em primeiro plano atual de uma tarefa ou serviço em segundo plano
Existe uma abordagem muito mais simples:
Em uma BaseActivity que todas as Atividades estendem:
Sempre que você precisar verificar se alguma de suas atividades de aplicativo está em primeiro plano, verifique
isVisible()
;Para entender essa abordagem, verifique esta resposta do ciclo de vida da atividade lado a lado : Ciclo de vida da atividade lado a lado
fonte
Idolon's answer is error prone
- infelizmente tenho que concordar com você. Com base no comentário de Dianne Hackborn nos Grupos do Google, atualizei minha resposta. Verifique-o por favor para os detalhes.onPause
,onStop
nem oonResume
evento é chamado. Então, o que você faz se nenhum desses eventos for acionado ?!Tentei a solução recomendada que usa Application.ActivityLifecycleCallbacks e muitos outros, mas eles não funcionaram conforme o esperado. Graças ao Sarge , eu vim com uma solução bastante fácil e direta que estou descrevendo abaixo.
Essa também é a principal diferença entre
onStop()
eonPause()
que nenhuma mencionou nos artigos que li.Portanto, com base no comportamento do ciclo de vida dessa atividade, você pode simplesmente contar quantas vezes foi
onStart()
eonPause()
foi chamado em seu programa. Observe que para cadaActivity
programa, você deve substituironStart()
eonStop()
, a fim de aumentar / diminuir a variável estática usada para a contagem. Abaixo está o código que implementa essa lógica. Observe que estou usando uma classe que se estendeApplication
; portanto, não se esqueça de declarar emManifest.xml
dentro da tag Application:,android:name=".Utilities"
embora possa ser implementada usando uma classe personalizada simples também.Agora, em cada Atividade do nosso programa, devemos substituir
onStart()
eonStop()
e aumentar / diminuir conforme mostrado abaixo:Com essa lógica, existem 2 casos possíveis:
stateCounter = 0
: O número de paradas é igual ao número de atividades iniciadas, o que significa que o aplicativo está sendo executado em segundo plano.stateCounter > 0
: O número de iniciados é maior que o número de interrompidos, o que significa que o aplicativo está sendo executado em primeiro plano.Aviso prévio:
stateCounter < 0
significaria que há mais atividades interrompidas do que iniciadas, o que é impossível. Se você encontrar esse caso, significa que não está aumentando / diminuindo o contador como deveria.Você está pronto para ir. Você deve verificar se seu aplicativo está em segundo plano por dentro
onStop()
.fonte
if(Utilities.isApplicationOnBackground()) …
paraUtilities
. Porque, caso contrário, apenas uma atividade específica reagirá ao evento.A menos que você mesmo o rastreie, não há como determinar se alguma de suas atividades é visível ou não. Talvez você deva pensar em fazer uma nova pergunta no StackOverflow, explicando o que você está tentando obter com a experiência do usuário, para que possamos fornecer idéias alternativas de implementação.
fonte
Service
. Nesse caso, faça com que suas atividades notifiquem o serviço à medida que aparecerem e desaparecerem. SeService
determinar que não há atividades visíveis e permanecer assim por algum tempo, pare a transferência de dados no próximo ponto de parada lógica. Sim, isso exigirá código para cada uma de suas atividades, mas, no momento, isso é inevitável para o AFAIK.MyActivityClass
herdaActivity
e implementa os métodos do ciclo de vida e fazer com que todas as suas atividades sejam herdadasMyActivityClass
. Este, sem trabalho paraPreferenceActivity
ouMapActivity
embora (ver esta questão )Você pode usar o ComponentCallbacks2 para detectar se o aplicativo está em segundo plano. BTW este retorno de chamada está disponível apenas na API Nível 14 (Ice Cream Sandwich) e acima.
Você receberá uma chamada para o método:
public abstract void onTrimMemory (int level)
se o nível é
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
, o aplicativo estará em segundo plano.Você pode implementar essa interface para um
activity
,service
etc.fonte
Com base no @Cornstalks, responda para incluir alguns recursos úteis.
Recursos extras:
App.java
AppLifecycleHandler.java
fonte
A melhor solução que eu criei usa temporizadores.
Você iniciou um timer em onPause () e cancelou o mesmo timer em onResume (); há 1 instância do Timer (geralmente definida na classe Application). O cronômetro propriamente dito está definido para executar um Runnable após 2 segundos (ou qualquer intervalo que você julgar apropriado), quando o cronômetro é acionado, você define um sinalizador que marca o aplicativo como em segundo plano.
No método onResume () antes de cancelar o timer, você pode consultar o sinalizador em segundo plano para executar qualquer operação de inicialização (por exemplo, iniciar downloads ou ativar os serviços de localização).
Esta solução permite que você tenha várias atividades na pilha de trás e não requer nenhuma permissão para implementar.
Essa solução funciona bem se você também usar um barramento de eventos, pois o timer pode simplesmente disparar um evento e várias partes do seu aplicativo podem responder de acordo.
fonte
Se você ativar as configurações do desenvolvedor "Não mantenha atividades" - verifique se apenas a contagem de atividades criadas não é suficiente. Você também deve verificar isSaveInstanceState . Minha verificação personalizada do método isApplicationRunning () está executando o aplicativo Android:
Aqui meu código de trabalho:
fonte
A única solução correta:
MainActivity.java:
MyApp.java:
fonte
Para pegar o que o CommonsWare e Key disseram, talvez você possa estender a classe Application e fazer com que todas as suas atividades chamem isso pelos métodos onPause / onResume. Isso permitiria que você soubesse quais atividades estão visíveis, mas isso provavelmente poderia ser tratado melhor.
Você pode elaborar exatamente o que tem em mente? Quando você diz que está executando em segundo plano, quer dizer simplesmente manter seu aplicativo na memória, mesmo que ele não esteja atualmente na tela? Você já pensou em usar os Serviços como uma maneira mais persistente de gerenciar seu aplicativo quando ele não está em foco?
fonte
Application
não temonPause()
ouonResume()
.Fiz minha própria implementação do ActivityLifecycleCallbacks. Estou usando SherlockActivity, mas para a classe Activity normal pode funcionar.
Primeiro, estou criando uma interface que possui todos os métodos para rastrear o ciclo de vida das atividades:
Segundo, implementei essa interface na classe do meu aplicativo:
Terceiro, estou criando uma classe que se estende do SherlockActivity:
Quarto, todas as classes que se estendem do SherlockActivity, substituí pelo MySherlockActivity:
Agora, no logcat, você verá os logs programados na implementação da interface feita no MyApplication.
fonte
A atividade é pausada quando um diálogo fica acima dele, portanto todas as soluções recomendadas são meias soluções. Você precisa criar ganchos para diálogos também.
fonte
Como ainda não foi mencionado, vou sugerir aos leitores que explorem o ProcessLifecycleOwner disponível através dos componentes da Arquitetura Android
fonte
Documentos oficiais:
O sistema distingue entre aplicativos em primeiro plano e em segundo plano. (A definição de plano de fundo para fins de limitações de serviço é distinta da definição usada pelo gerenciamento de memória; um aplicativo pode estar em segundo plano no que diz respeito ao gerenciamento de memória , mas em primeiro plano no que diz respeito à sua capacidade de iniciar serviços.) considerado em primeiro plano se alguma das seguintes situações for verdadeira:
Se nenhuma dessas condições for verdadeira, o aplicativo será considerado em segundo plano.
fonte
Outra solução para este post antigo (para aqueles que podem ajudar):
fonte
Veja o comentário na função onActivityDestroyed.
Funciona com o destino SDK versão 14>:
fonte
Você deve usar uma preferência compartilhada para armazenar a propriedade e agir de acordo com ela usando a ligação de serviço de suas atividades. Se você usar apenas a ligação (que nunca usa startService), seu serviço será executado apenas quando você se vincular a ele (bind onResume e unbind onPause) que o executaria apenas em primeiro plano e se desejar trabalhar em Em segundo plano, você pode usar o serviço de parada de partida regular.
fonte
Eu acho que essa pergunta deveria ser mais clara. Quando? Onde? Qual é a sua situação específica que você deseja saber se o aplicativo estiver em segundo plano?
Acabei de apresentar minha solução do meu jeito.
Consigo fazer isso usando o campo "importância" da
RunningAppProcessInfo
classe noonStop
método de todas as atividades do meu aplicativo, o que pode ser alcançado simplesmente fornecendo umaBaseActivity
extensão para outras atividades que implementam oonStop
método para verificar o valor de "importância". Aqui está o código:fonte
Eu recomendo a leitura desta página: http://developer.android.com/reference/android/app/Activity.html
Em suma, sua atividade não é mais visível após a
onStop()
chamada.fonte
onStop
; entreonPause
eonStop
é visível , mas não em primeiro plano .onStop()
é chamada, alinhada com o que você escreveu.onPause
é chamado: uma edição recente o corrigiu.Que tal usar getApplicationState (). IsInForeground ()?
fonte
Na minha opinião, muitas respostas introduzem uma carga pesada de código e traz muita complexidade e falta de legibilidade.
Quando as pessoas perguntam sobre como se comunicar entre a
Service
e aActivity
, geralmente aconselho usar o LocalBroadcastManager .Por quê?
Bem, citando os documentos:
Não está nos documentos:
Activity
,Application
...Descrição
Portanto, você deseja verificar se algum dos itens
Activity
está atualmente em primeiro plano. Você costuma fazer isso em uma aulaService
ou na suaApplication
classe.Isso significa que seus
Activity
objetos se tornam o remetente de um sinal (estou ligado / desligado). SeuService
, por outro lado, se torna oReceiver
.Existem dois momentos em que seu
Activity
você diz se está indo em primeiro plano ou em segundo plano (sim, apenas dois ... não 6).Quando
Activity
entra em primeiro plano, oonResume()
método é acionado (também chamado apósonCreate()
).Quando
Activity
vai pelas costas,onPause()
é chamado.Estes são os momentos em que você
Activity
deve enviar o sinal para o seuService
para descrever seu estado.No caso de múltiplos
Activity
, lembre-se doActivity
se de que o primeiro entra em segundo plano e depois outro entra em primeiro plano.Então a situação seria: *
O
Service
/Application
continuará ouvindo esses sinais e agirá de acordo.Código (TLDR)
Você
Service
deve implementar umBroadcastReceiver
para ouvir sinais.Registre o
Receiver
emService::onCreate()
Cancele o registro em
Service::onDestroy()
Agora o seu
Activity
deve comunicar o estado deles.No
Activity::onResume()
No
Activity::onPause()
Uma situação muito, muito comum
Geralmente, não é necessário verificar se
Activity
o item está em primeiro plano ou não. Basta enviar os dados viaLocalBroadcastManager
do seuService
. SeActivity
estiver ativado, ele responderá e agirá.Para esta situação muito comum, o
Service
torna-se o remetente e oActivity
implementa oBroadcastReceiver
.Então, crie um
Receiver
no seuActivity
. Registre-oonResume()
e cancele o registroonPause()
. Não há necessidade de usar os outros métodos de ciclo de vida .Defina o
Receiver
comportamento emonReceive()
(atualize o ListView, faça isso, faça aquilo, ...).Dessa forma, o
Activity
ouvirá apenas se estiver em primeiro plano e nada acontecerá se estiver nas costas ou for destruído.No caso de múltiplos
Activity
, o queActivity
estiver ativado responderá (se eles também implementarem oReceiver
).Se tudo estiver em segundo plano, ninguém responderá e o sinal simplesmente se perderá.
Envie os dados da
Service
viaIntent
(consulte o código acima) especificando o ID do sinal.fonte
fonte
Nenhuma das respostas se encaixava perfeitamente no caso específico se você procurasse saber se uma atividade específica está em andamento e se você é um SDK sem acesso direto ao Aplicativo. Para mim, eu estava no segmento de segundo plano, tendo recebido apenas uma notificação por push para uma nova mensagem de bate-papo e só quero exibir uma notificação do sistema se a tela de bate-papo não estiver em primeiro plano.
Usando o
ActivityLifecycleCallbacks
que foi recomendado em outras respostas, criei uma pequena classe util que abriga a lógica paraMyActivity
estar ou não em primeiro plano.}
fonte
Nas minhas atividades onResume e onPause, escrevo um booleano isVisible em SharedPrefences.
E leia em outro lugar quando necessário via,
Talvez não seja elegante, mas funciona para mim ...
fonte
Talvez seja tarde demais para responder, mas se alguém vier visitar, aqui está a solução que eu sugiro: o (s) motivo (s) pelo qual um aplicativo deseja saber que está em segundo plano ou que está em primeiro plano pode ser muitos, alguns são 1. Para mostrar brindes e notificações quando o usuário estiver no BG. 2.Para executar algumas tarefas pela primeira vez, o usuário vem do BG, como uma enquete, redesenho etc.
A solução de Idolon e outros cuida da primeira parte, mas não da segunda. Se houver várias atividades no seu aplicativo e o usuário estiver alternando entre elas, quando você estiver na segunda atividade, o sinalizador visível será falso. Portanto, não pode ser usado deterministicamente.
Fiz algo que foi sugerido pelo CommonsWare: "Se o Serviço determinar que não há atividades visíveis e permanecer assim por algum tempo , pare a transferência de dados no próximo ponto de parada lógica".
A linha em negrito é importante e isso pode ser usado para alcançar o segundo item. Portanto, o que eu faço é quando obtenho o onActivityPaused (), não altere o visible para false diretamente, em vez disso, tenho um temporizador de 3 segundos (é o máximo que a próxima atividade deve ser iniciada) e, se não houver onActivityResumed ( ) nos próximos 3 segundos, mude de visível para falso. Da mesma forma em onActivityResumed () se houver um timer, eu o cancelo. Para resumir, o visível se torna isAppInBackground.
Desculpe, não é possível copiar e colar o código ...
fonte
Eu gostaria de recomendar que você use outra maneira de fazer isso.
Eu acho que você deseja mostrar a tela de inicialização enquanto o programa está sendo iniciado, se já estiver sendo executado no back-end, não o mostre.
Seu aplicativo pode gravar continuamente a hora atual em um arquivo específico. Enquanto o aplicativo está sendo iniciado, verifique o último registro de data e hora, se current_time-last_time> o período especificado para a gravação do horário mais recente, significa que o aplicativo foi parado, interrompido pelo sistema ou pelo próprio usuário.
fonte