Sto cercando di scrivere un'app che fa qualcosa di specifico quando viene riportata in primo piano dopo un certo periodo di tempo. Esiste un modo per rilevare quando un'app viene inviata in background o portata in primo piano?
Sto cercando di scrivere un'app che fa qualcosa di specifico quando viene riportata in primo piano dopo un certo periodo di tempo. Esiste un modo per rilevare quando un'app viene inviata in background o portata in primo piano?
Risposte:
I metodi onPause()
e onResume()
vengono chiamati quando l'applicazione viene portata in background e di nuovo in primo piano. Tuttavia, vengono anche chiamati quando l'applicazione viene avviata per la prima volta e prima che venga uccisa. Puoi leggere di più in Attività .
Non esiste alcun approccio diretto per ottenere lo stato dell'applicazione in background o in primo piano, ma anche io ho affrontato questo problema e ho trovato la soluzione con onWindowFocusChanged
e onStop
.
Per maggiori dettagli, consulta qui Android: soluzione per rilevare quando un'app Android passa in background e torna in primo piano senza getRunningTasks o getRunningAppProcesses .
AGGIORNAMENTO di marzo 2018 : ora esiste una soluzione migliore. Vedi ProcessLifecycleOwner . Dovrai utilizzare i nuovi componenti dell'architettura 1.1.0 (la più recente in questo momento) ma è specificamente progettato per farlo.
C'è un semplice esempio fornito in questa risposta, ma ho scritto un'app di esempio e un post sul blog a riguardo.
Da quando l'ho scritto nel 2014, sono nate diverse soluzioni. Alcuni hanno funzionato, altri si pensava funzionassero , ma avevano difetti (incluso il mio!) E noi, come comunità (Android), abbiamo imparato a convivere con le conseguenze e abbiamo scritto soluzioni alternative per i casi speciali.
Non dare per scontato che un singolo frammento di codice sia la soluzione che stai cercando, è improbabile che sia così; meglio ancora, cerca di capire cosa fa e perché lo fa.
La MemoryBoss
classe non è mai stata effettivamente utilizzata da me come scritto qui, era solo un pezzo di pseudo codice che funzionava.
A meno che non ci sia una ragione valida per non usare i nuovi componenti dell'architettura (e ce ne sono alcuni, specialmente se si prendono di mira le vecchie vecchie API), quindi andare avanti e usarli. Sono tutt'altro che perfetti, ma nessuno dei due lo era ComponentCallbacks2
.
AGGIORNAMENTO / NOTE (novembre 2015) : le persone hanno fatto due commenti, il primo è che >=
dovrebbe essere usato invece che ==
perché la documentazione afferma che non si dovrebbero verificare i valori esatti . Questo va bene per la maggior parte dei casi, ma tenere a mente che se solo si cura di fare qualcosa quando l'applicazione è andato al fondo, si dovrà utilizzare == e anche combinarlo con un'altra soluzione (come callback attività del ciclo di vita), oppure si potrebbe non ottenere l'effetto desiderato. L'esempio (e questo è successo a me) è che se vuoi bloccarela tua app con una schermata della password quando passa in background (come 1Password se la conosci), potresti accidentalmente bloccare l'app se hai poca memoria e stai improvvisamente testando >= TRIM_MEMORY
, perché Android attiverà una LOW MEMORY
chiamata e questo è più alto del tuo. Quindi fai attenzione a come / cosa testare.
Inoltre, alcune persone hanno chiesto come rilevare quando torni.
Il modo più semplice a cui riesco a pensare è spiegato di seguito, ma dato che alcune persone non lo conoscono, sto aggiungendo un pseudo codice proprio qui. Supponendo che tu abbia YourApplication
e le MemoryBoss
classi, nel tuo class BaseActivity extends Activity
(dovrai crearne una se non ne hai una).
@Override
protected void onStart() {
super.onStart();
if (mApplication.wasInBackground()) {
// HERE YOU CALL THE CODE YOU WANT TO HAPPEN ONLY ONCE WHEN YOUR APP WAS RESUMED FROM BACKGROUND
mApplication.setWasInBackground(false);
}
}
Raccomando onStart perché le finestre di dialogo possono mettere in pausa un'attività, quindi scommetto che non vuoi che la tua app pensi "è andata in secondo piano" se tutto ciò che hai fatto è stato visualizzare una finestra di dialogo a schermo intero, ma il tuo chilometraggio può variare.
E questo è tutto. Il codice nel blocco if sarà eseguito solo una volta , anche se si va a un'altra attività, quello nuovo (che anche extends BaseActivity
) riferirà wasInBackground
è false
in modo da non eseguire il codice, fino a quando onMemoryTrimmed
viene chiamato e il flag è impostato su true nuovo .
Spero che aiuti.
AGGIORNAMENTO / NOTE (aprile 2015) : Prima di andare su Copia e incolla su questo codice, nota che ho trovato un paio di casi in cui potrebbe non essere affidabile al 100% e devo combinarlo con altri metodi per ottenere i migliori risultati. In particolare, ci sono due casi noti in cui onTrimMemory
non è garantita l'esecuzione della richiamata:
Se il telefono blocca lo schermo mentre l'app è visibile (diciamo che il dispositivo si blocca dopo nn minuti), questo callback non viene chiamato (o non sempre) perché la schermata di blocco è solo in cima, ma l'app è ancora "in esecuzione" anche se coperta.
Se il tuo dispositivo ha una memoria relativamente bassa (e sotto stress di memoria), il sistema operativo sembra ignorare questa chiamata e passare direttamente a livelli più critici.
Ora, a seconda di quanto sia importante che tu sappia quando la tua app è passata in background, potresti aver bisogno o meno di estendere questa soluzione insieme per tenere traccia del ciclo di vita delle attività e quant'altro.
Tieni a mente quanto sopra e fai in modo di avere un buon team di controllo qualità;)
FINE AGGIORNAMENTO
Potrebbe essere tardi, ma esiste un metodo affidabile in Ice Cream Sandwich (API 14) e versioni successive .
Si scopre che quando l'app non ha più un'interfaccia utente visibile, viene attivato un callback. Il callback, che è possibile implementare in una classe personalizzata, si chiama ComponentCallbacks2 (sì, con un due). Questo callback è disponibile solo in API Level 14 (Ice Cream Sandwich) e versioni successive.
Praticamente ricevi una chiamata al metodo:
public abstract void onTrimMemory (int level)
Il livello è 20 o più specificamente
public static final int TRIM_MEMORY_UI_HIDDEN
Ho provato questo e funziona sempre, perché il livello 20 è solo un "suggerimento" che potresti voler rilasciare alcune risorse poiché la tua app non è più visibile.
Per citare i documenti ufficiali:
Livello per onTrimMemory (int): il processo mostrava un'interfaccia utente e non lo fa più. A questo punto è necessario rilasciare grandi allocazioni con l'interfaccia utente per consentire una migliore gestione della memoria.
Ovviamente, dovresti implementarlo per fare effettivamente ciò che dice (elimina la memoria che non è stata utilizzata in un determinato momento, cancella alcune raccolte che sono rimaste inutilizzate, ecc. Le possibilità sono infinite (vedi i documenti ufficiali per altri possibili altro livelli critici ).
Ma la cosa interessante è che il sistema operativo ti sta dicendo: HEY, la tua app è passata in secondo piano!
Che è esattamente quello che volevi sapere in primo luogo.
Come determini quando sei tornato?
Bene, è facile, sono sicuro che hai un "BaseActivity" in modo da poter usare onResume () per segnalare il fatto che sei tornato. Perché l'unica volta che dirai che non sei tornato è quando ricevi effettivamente una chiamata al onTrimMemory
metodo sopra .
Funziona. Non ottieni falsi positivi. Se un'attività riprende, sei tornato, il 100% delle volte. Se l'utente torna di nuovo sul retro, si riceve un'altra onTrimMemory()
chiamata.
Devi iscrivere le tue attività (o meglio ancora, un corso personalizzato).
Il modo più semplice per garantirti di ricevere sempre questo è creare una classe semplice come questa:
public class MemoryBoss implements ComponentCallbacks2 {
@Override
public void onConfigurationChanged(final Configuration newConfig) {
}
@Override
public void onLowMemory() {
}
@Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
// We're in the Background
}
// you might as well implement some memory cleanup here and be a nice Android dev.
}
}
Per usarlo, nell'implementazione dell'applicazione ( ne hai uno, DESTRA? ), Fai qualcosa del tipo:
MemoryBoss mMemoryBoss;
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
mMemoryBoss = new MemoryBoss();
registerComponentCallbacks(mMemoryBoss);
}
}
Se si crea un, Interface
è possibile aggiungere un else
a quello if
e implementare ComponentCallbacks
(senza il 2) utilizzato in qualsiasi cosa sotto API 14. Quel callback ha solo il onLowMemory()
metodo e non viene chiamato quando si passa in background , ma è necessario utilizzarlo per tagliare la memoria .
Ora avvia l'app e premi home. Il tuo onTrimMemory(final int level)
metodo dovrebbe essere chiamato (suggerimento: aggiungi registrazione).
L'ultimo passaggio consiste nell'annullare la registrazione dal callback. Probabilmente il posto migliore è il onTerminate()
metodo della tua app, ma quel metodo non viene chiamato su un dispositivo reale:
/** * This method is for use in emulated process environments. It will * never be called on a production Android device, where processes are * removed by simply killing them; no user code (including this callback) * is executed when doing so. */
Quindi, a meno che tu non abbia davvero una situazione in cui non desideri più essere registrato, puoi tranquillamente ignorarlo, poiché il tuo processo sta comunque morendo a livello di sistema operativo.
Se decidi di annullare la registrazione a un certo punto (se, ad esempio, fornisci un meccanismo di arresto per la tua app per ripulire e morire), puoi fare:
unregisterComponentCallbacks(mMemoryBoss);
E questo è tutto.
level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
che evita il problema nel tuo aggiornamento, punto 2. Per quanto riguarda il punto 1, non è un problema per me, poiché l'app non è andata davvero in secondo piano, quindi è così che dovrebbe funzionare.
Ecco come sono riuscito a risolverlo. Funziona sul presupposto che l'utilizzo di un riferimento temporale tra le transizioni di attività fornirà molto probabilmente prove adeguate che un'app è stata "in background" o meno.
Innanzitutto, ho usato un'istanza android.app.Application (chiamiamola MyApplication) che ha un Timer, un TimerTask, una costante per rappresentare il numero massimo di millisecondi che la transizione da un'attività all'altra potrebbe ragionevolmente richiedere (sono andato con un valore di 2s) e un valore booleano per indicare se l'app era "in background" o meno:
public class MyApplication extends Application {
private Timer mActivityTransitionTimer;
private TimerTask mActivityTransitionTimerTask;
public boolean wasInBackground;
private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000;
...
L'applicazione fornisce anche due metodi per l'avvio e l'arresto del timer / attività:
public void startActivityTransitionTimer() {
this.mActivityTransitionTimer = new Timer();
this.mActivityTransitionTimerTask = new TimerTask() {
public void run() {
MyApplication.this.wasInBackground = true;
}
};
this.mActivityTransitionTimer.schedule(mActivityTransitionTimerTask,
MAX_ACTIVITY_TRANSITION_TIME_MS);
}
public void stopActivityTransitionTimer() {
if (this.mActivityTransitionTimerTask != null) {
this.mActivityTransitionTimerTask.cancel();
}
if (this.mActivityTransitionTimer != null) {
this.mActivityTransitionTimer.cancel();
}
this.wasInBackground = false;
}
L'ultimo pezzo di questa soluzione è aggiungere una chiamata a ciascuno di questi metodi dagli eventi onResume () e onPause () di tutte le attività o, preferibilmente, in un'attività di base da cui ereditano tutte le attività concrete:
@Override
public void onResume()
{
super.onResume();
MyApplication myApp = (MyApplication)this.getApplication();
if (myApp.wasInBackground)
{
//Do specific came-here-from-background code
}
myApp.stopActivityTransitionTimer();
}
@Override
public void onPause()
{
super.onPause();
((MyApplication)this.getApplication()).startActivityTransitionTimer();
}
Quindi, nel caso in cui l'utente stia semplicemente navigando tra le attività della tua app, onPause () dell'attività in partenza avvia il timer, ma quasi immediatamente la nuova attività immessa annulla il timer prima che possa raggiungere il tempo di transizione massimo. E così anche InBackground sarebbe falso .
D'altra parte, quando un'attività viene in primo piano dal Launcher, il dispositivo si sveglia, termina la chiamata, ecc., Molto probabilmente l'attività del timer eseguita prima di questo evento, e quindi wasInBackground era impostata su true .
Modifica: i nuovi componenti dell'architettura hanno portato qualcosa di promettente: ProcessLifecycleOwner , vedi la risposta di @ vokilam
class YourApplication : Application() {
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(AppLifecycleTracker())
}
}
class AppLifecycleTracker : Application.ActivityLifecycleCallbacks {
private var numStarted = 0
override fun onActivityStarted(activity: Activity?) {
if (numStarted == 0) {
// app went to foreground
}
numStarted++
}
override fun onActivityStopped(activity: Activity?) {
numStarted--
if (numStarted == 0) {
// app went to background
}
}
}
Sì. So che è difficile credere che questa semplice soluzione funzioni dal momento che abbiamo così tante soluzioni strane qui.
Ma c'è speranza.
ProcessLifecycleOwner
sembra essere anche una soluzione promettente.
ProcessLifecycleOwner invierà
ON_START
,ON_RESUME
eventi, come una prima attività si muove attraverso questi eventi.ON_PAUSE
, gliON_STOP
eventi verranno inviati con un ritardo dopo che un'ultima attività li ha attraversati. Questo ritardo è abbastanza lungo da garantire cheProcessLifecycleOwner
non invierà alcun evento se le attività vengono distrutte e ricreate a causa di una modifica della configurazione.
Un'implementazione può essere semplice come
class AppLifecycleListener : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onMoveToForeground() { // app moved to foreground
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onMoveToBackground() { // app moved to background
}
}
// register observer
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleListener())
Secondo il codice sorgente, il valore di ritardo corrente è 700ms
.
Anche l'utilizzo di questa funzione richiede dependencies
:
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"
implementation "android.arch.lifecycle:extensions:1.0.0"
e annotationProcessor "android.arch.lifecycle:compiler:1.0.0"
dal repository di Google (es. google()
)
Sulla base della risposta di Martín Marconcinis (grazie!) Ho finalmente trovato una soluzione affidabile (e molto semplice).
public class ApplicationLifecycleHandler implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {
private static final String TAG = ApplicationLifecycleHandler.class.getSimpleName();
private static boolean isInBackground = false;
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
if(isInBackground){
Log.d(TAG, "app went to foreground");
isInBackground = false;
}
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onConfigurationChanged(Configuration configuration) {
}
@Override
public void onLowMemory() {
}
@Override
public void onTrimMemory(int i) {
if(i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN){
Log.d(TAG, "app went to background");
isInBackground = true;
}
}
}
Quindi aggiungilo a onCreate () della tua classe Application
public class MyApp extends android.app.Application {
@Override
public void onCreate() {
super.onCreate();
ApplicationLifeCycleHandler handler = new ApplicationLifeCycleHandler();
registerActivityLifecycleCallbacks(handler);
registerComponentCallbacks(handler);
}
}
Usiamo questo metodo. Sembra troppo semplice per funzionare, ma è stato ben testato nella nostra app e in effetti funziona sorprendentemente bene in tutti i casi, incluso andare alla schermata principale con il pulsante "home", con il pulsante "return" o dopo il blocco dello schermo. Provaci.
L'idea è, quando in primo piano, Android inizia sempre una nuova attività poco prima di interrompere quella precedente. Non è garantito, ma funziona così. A proposito, Flurry sembra usare la stessa logica (solo una supposizione, non l'ho verificato, ma si aggancia agli stessi eventi).
public abstract class BaseActivity extends Activity {
private static int sessionDepth = 0;
@Override
protected void onStart() {
super.onStart();
sessionDepth++;
if(sessionDepth == 1){
//app came to foreground;
}
}
@Override
protected void onStop() {
super.onStop();
if (sessionDepth > 0)
sessionDepth--;
if (sessionDepth == 0) {
// app went to background
}
}
}
Modifica: come da commenti, ci siamo anche spostati su onStart () nelle versioni successive del codice. Inoltre, sto aggiungendo super chiamate, che mancavano dal mio post iniziale, perché questo era più un concetto che un codice funzionante.
onStop is called when the activity is no longer visible to the user
.
Se la tua app è composta da più attività e / o attività in pila come un widget della barra delle schede, la sostituzione di onPause () e onResume () non funzionerà. Vale a dire quando si avvia una nuova attività le attività correnti verranno messe in pausa prima che la nuova venga creata. Lo stesso vale quando si termina (usando il pulsante "indietro") un'attività.
Ho trovato due metodi che sembrano funzionare come desiderato.
Il primo richiede l'autorizzazione GET_TASKS ed è costituito da un metodo semplice che controlla se l'attività principale in esecuzione sul dispositivo appartiene all'applicazione, confrontando i nomi dei pacchetti:
private boolean isApplicationBroughtToBackground() {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
return true;
}
}
return false;
}
Questo metodo è stato trovato nel framework Droid-Fu (ora chiamato Ignition).
Il secondo metodo che ho implementato da solo non richiede l'autorizzazione GET_TASKS, il che è positivo. Invece è un po 'più complicato da implementare.
Nella tua classe MainApplication hai una variabile che tiene traccia del numero di attività in esecuzione nella tua applicazione. In onResume () per ogni attività aumenti la variabile e in onPause () la diminuisci.
Quando il numero di attività in esecuzione raggiunge 0, l'applicazione viene messa in background SE sono vere le seguenti condizioni:
Quando è possibile rilevare che l'applicazione si è dimessa in background, è facile rilevare anche quando viene riportata in primo piano.
Crea una classe che si estende Application
. Poi in esso possiamo usare il suo metodo di sostituzione, onTrimMemory()
.
Per rilevare se l'applicazione è passata in background, utilizzeremo:
@Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // Works for Activity
// Get called every-time when application went to background.
}
else if (level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { // Works for FragmentActivty
}
}
FragmentActivity
te potresti voler aggiungere level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE
anche.
Prendi in considerazione l'utilizzo di onUserLeaveHint. Questo verrà chiamato solo quando l'app passa in background. onPause avrà casi angolari da gestire, poiché può essere chiamato per altri motivi; ad esempio se l'utente apre un'altra attività nella tua app come la pagina delle impostazioni, il metodo onPause della tua attività principale verrà chiamato anche se sono ancora nella tua app; tenere traccia di ciò che sta accadendo porterà a bug quando invece puoi semplicemente usare il callback onUserLeaveHint che fa quello che stai chiedendo.
Quando si chiama UserLeaveHint, è possibile impostare un flag booleano inBackground su true. Quando viene chiamato onResume, supponi di essere tornato in primo piano solo se è impostato il flag inBackground. Questo perché onResume verrà chiamato anche sulla tua attività principale se l'utente si trovava nel menu delle impostazioni e non ha mai lasciato l'app.
Ricorda che se l'utente preme il pulsante Home mentre si trova nella schermata delle impostazioni, onUserLeaveHint verrà richiamato nell'attività delle impostazioni e quando ritorna acceso, verrà richiamato Ripristino nell'attività delle impostazioni. Se hai solo questo codice di rilevamento nella tua attività principale, perderai questo caso d'uso. Per avere questo codice in tutte le tue attività senza duplicare il codice, disponi di una classe di attività astratta che estende l'attività e inserisci il tuo codice comune. Quindi ogni attività che hai può estendere questa attività astratta.
Per esempio:
public abstract AbstractActivity extends Activity {
private static boolean inBackground = false;
@Override
public void onResume() {
if (inBackground) {
// You just came from the background
inBackground = false;
}
else {
// You just returned from another activity within your own app
}
}
@Override
public void onUserLeaveHint() {
inBackground = true;
}
}
public abstract MainActivity extends AbstractActivity {
...
}
public abstract SettingsActivity extends AbstractActivity {
...
}
ActivityLifecycleCallbacks potrebbe essere interessante, ma non è ben documentato.
Tuttavia, se si chiama registerActivityLifecycleCallbacks (), si dovrebbe essere in grado di ottenere richiamate per quando le attività vengono create, distrutte, ecc. È possibile chiamare getComponentName () per l'attività.
Il pacchetto android.arch.lifecycle fornisce classi e interfacce che ti consentono di creare componenti sensibili al ciclo di vita
L'applicazione deve implementare l'interfaccia LifecycleObserver:
public class MyApplication extends Application implements LifecycleObserver {
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
private void onAppBackgrounded() {
Log.d("MyApp", "App in background");
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
private void onAppForegrounded() {
Log.d("MyApp", "App in foreground");
}
}
Per fare ciò, devi aggiungere questa dipendenza al tuo file build.gradle:
dependencies {
implementation "android.arch.lifecycle:extensions:1.1.1"
}
Come raccomandato da Google, è necessario ridurre al minimo il codice eseguito nei metodi di ciclo di vita delle attività:
Un modello comune è implementare le azioni dei componenti dipendenti nei metodi del ciclo di vita di attività e frammenti. Tuttavia, questo modello porta a una cattiva organizzazione del codice e alla proliferazione degli errori. Utilizzando componenti compatibili con il ciclo di vita, è possibile spostare il codice dei componenti dipendenti dai metodi del ciclo di vita e nei componenti stessi.
Puoi leggere di più qui: https://developer.android.com/topic/libraries/architecture/lifecycle
Nella tua applicazione aggiungi il callback e controlla l'attività di root in questo modo:
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
if (activity.isTaskRoot() && !(activity instanceof YourSplashScreenActivity)) {
Log.e(YourApp.TAG, "Reload defaults on restoring from background.");
loadDefaults();
}
}
});
}
Ho creato un progetto su Github app-foreground-background-hear
Crea una BaseActivity per tutte le attività nella tua applicazione.
public class BaseActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
public static boolean isAppInFg = false;
public static boolean isScrInFg = false;
public static boolean isChangeScrFg = false;
@Override
protected void onStart() {
if (!isAppInFg) {
isAppInFg = true;
isChangeScrFg = false;
onAppStart();
}
else {
isChangeScrFg = true;
}
isScrInFg = true;
super.onStart();
}
@Override
protected void onStop() {
super.onStop();
if (!isScrInFg || !isChangeScrFg) {
isAppInFg = false;
onAppPause();
}
isScrInFg = false;
}
public void onAppStart() {
// Remove this toast
Toast.makeText(getApplicationContext(), "App in foreground", Toast.LENGTH_LONG).show();
// Your code
}
public void onAppPause() {
// Remove this toast
Toast.makeText(getApplicationContext(), "App in background", Toast.LENGTH_LONG).show();
// Your code
}
}
Ora usa BaseActivity come una super classe di tutte le tue attività come MainActivity estende BaseActivity e onAppStart verrà chiamato quando avvii l'applicazione e onAppPause () verrà chiamato quando l'applicazione passa in background da qualsiasi schermata.
Questo è abbastanza facile con ProcessLifecycleOwner
Aggiungi queste dipendenze
implementation "android.arch.lifecycle:extensions:$project.archLifecycleVersion"
kapt "android.arch.lifecycle:compiler:$project.archLifecycleVersion"
A Kotlin :
class ForegroundBackgroundListener : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun startSomething() {
Log.v("ProcessLog", "APP IS ON FOREGROUND")
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun stopSomething() {
Log.v("ProcessLog", "APP IS IN BACKGROUND")
}
}
Quindi nella tua attività di base:
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get()
.lifecycle
.addObserver(
ForegroundBackgroundListener()
.also { appObserver = it })
}
Vedi il mio articolo su questo argomento: https://medium.com/@egek92/how-to-actually-detect-foreground-background-changes-in-your-android-application-without-wanting-9719cc822c48
È possibile utilizzare ProcessLifecycleOwner collegando ad esso un osservatore del ciclo di vita.
public class ForegroundLifecycleObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onAppCreated() {
Timber.d("onAppCreated() called");
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppStarted() {
Timber.d("onAppStarted() called");
}
@OnLifecycleEvent(Event.ON_RESUME)
public void onAppResumed() {
Timber.d("onAppResumed() called");
}
@OnLifecycleEvent(Event.ON_PAUSE)
public void onAppPaused() {
Timber.d("onAppPaused() called");
}
@OnLifecycleEvent(Event.ON_STOP)
public void onAppStopped() {
Timber.d("onAppStopped() called");
}
}
quindi nella onCreate()
classe della tua Applicazione chiami questo:
ProcessLifecycleOwner.get().getLifecycle().addObserver(new ForegroundLifecycleObserver());
con questo sarai in grado di catturare gli eventi di ON_PAUSE
e ON_STOP
della tua applicazione che si verificano quando va in background.
Non ci sono metodi di ciclo di vita semplici per dirti quando l'intera applicazione passa in primo piano.
L'ho fatto in modo semplice. Seguire le istruzioni seguenti per rilevare la fase di background / primo piano dell'applicazione.
Con un po 'di soluzione, è possibile. Qui ActivityLifecycleCallbacks viene in soccorso. Lasciami fare un passo alla volta.
Innanzitutto, crea una classe che estende android.app.Application e implementa l' interfaccia ActivityLifecycleCallbacks . In Application.onCreate (), registrare il callback.
public class App extends Application implements
Application.ActivityLifecycleCallbacks {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
}
Registrare la classe “App” nel Manifesto come sotto, <application android:name=".App"
.
Ci sarà almeno un'attività nello stato di avvio quando l'app è in primo piano e non ci sarà attività nello stato di avvio quando l'app è in background.
Dichiarare 2 variabili come di seguito nella classe "App".
private int activityReferences = 0;
private boolean isActivityChangingConfigurations = false;
activityReferences
manterrà il conteggio del numero di attività nel stato avviato . isActivityChangingConfigurations
è un flag per indicare se l'attività corrente sta attraversando un cambiamento di configurazione come un interruttore di orientamento.
Utilizzando il seguente codice è possibile rilevare se l'app viene visualizzata in primo piano.
@Override
public void onActivityStarted(Activity activity) {
if (++activityReferences == 1 && !isActivityChangingConfigurations) {
// App enters foreground
}
}
Ecco come rilevare se l'app passa in background.
@Override
public void onActivityStopped(Activity activity) {
isActivityChangingConfigurations = activity.isChangingConfigurations();
if (--activityReferences == 0 && !isActivityChangingConfigurations) {
// App enters background
}
}
Come funziona:
Questo è un piccolo trucco fatto con il modo in cui i metodi del ciclo di vita sono chiamati in sequenza. Vorrei illustrare uno scenario.
Si supponga che l'utente avvii l'app e che venga avviata l'attività di avvio A. Le chiamate del ciclo di vita saranno,
A.onCreate ()
A.onStart () (++ activityReferences == 1) (L'app entra in primo piano)
A.onResume ()
Ora l'attività A avvia l'attività B.
A.onPause ()
B.onCreate ()
B.onStart () (++ activityReferences == 2)
B.onResume ()
A.onStop () (--activityReferences == 1)
Quindi l'utente torna indietro dall'attività B,
B.onPause ()
A.onStart () (++ activityReferences == 2)
A.onResume ()
B.onStop () (--activityReferences == 1)
B.onDestroy ()
Quindi l'utente preme il pulsante Home,
A.onPause ()
A.onStop () (--activityReferences == 0) (L'app entra in background)
Nel caso, se l'utente preme il pulsante Home dall'attività B invece del pulsante Indietro, sarà sempre lo stesso e attivitàReferenze saranno 0
. Quindi, possiamo rilevare come l'app che entra in background.
Quindi, qual è il ruolo di isActivityChangingConfigurations
? Nello scenario sopra, supponiamo che l'attività B cambi l'orientamento. La sequenza di richiamata sarà,
B.onPause ()
B.onStop () (--activityReferences == 0) (L'app entra in Background ??)
B.onDestroy ()
B.onCreate ()
B.onStart () (++ activityReferences == 1) (L'app entra in primo piano ??)
B.onResume ()
Ecco perché abbiamo un ulteriore controllo isActivityChangingConfigurations
per evitare lo scenario quando l'attività sta attraversando le modifiche alla configurazione.
Ho trovato un buon metodo per rilevare l'applicazione sia in primo piano che in background. Ecco il mio codice . Spero che questo ti aiuti.
/**
* Custom Application which can detect application state of whether it enter
* background or enter foreground.
*
* @reference http://www.vardhan-justlikethat.blogspot.sg/2014/02/android-solution-to-detect-when-android.html
*/
public abstract class StatusApplication extends Application implements ActivityLifecycleCallbacks {
public static final int STATE_UNKNOWN = 0x00;
public static final int STATE_CREATED = 0x01;
public static final int STATE_STARTED = 0x02;
public static final int STATE_RESUMED = 0x03;
public static final int STATE_PAUSED = 0x04;
public static final int STATE_STOPPED = 0x05;
public static final int STATE_DESTROYED = 0x06;
private static final int FLAG_STATE_FOREGROUND = -1;
private static final int FLAG_STATE_BACKGROUND = -2;
private int mCurrentState = STATE_UNKNOWN;
private int mStateFlag = FLAG_STATE_BACKGROUND;
@Override
public void onCreate() {
super.onCreate();
mCurrentState = STATE_UNKNOWN;
registerActivityLifecycleCallbacks(this);
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
// mCurrentState = STATE_CREATED;
}
@Override
public void onActivityStarted(Activity activity) {
if (mCurrentState == STATE_UNKNOWN || mCurrentState == STATE_STOPPED) {
if (mStateFlag == FLAG_STATE_BACKGROUND) {
applicationWillEnterForeground();
mStateFlag = FLAG_STATE_FOREGROUND;
}
}
mCurrentState = STATE_STARTED;
}
@Override
public void onActivityResumed(Activity activity) {
mCurrentState = STATE_RESUMED;
}
@Override
public void onActivityPaused(Activity activity) {
mCurrentState = STATE_PAUSED;
}
@Override
public void onActivityStopped(Activity activity) {
mCurrentState = STATE_STOPPED;
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
mCurrentState = STATE_DESTROYED;
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if (mCurrentState == STATE_STOPPED && level >= TRIM_MEMORY_UI_HIDDEN) {
if (mStateFlag == FLAG_STATE_FOREGROUND) {
applicationDidEnterBackground();
mStateFlag = FLAG_STATE_BACKGROUND;
}
}else if (mCurrentState == STATE_DESTROYED && level >= TRIM_MEMORY_UI_HIDDEN) {
if (mStateFlag == FLAG_STATE_FOREGROUND) {
applicationDidDestroyed();
mStateFlag = FLAG_STATE_BACKGROUND;
}
}
}
/**
* The method be called when the application been destroyed. But when the
* device screen off,this method will not invoked.
*/
protected abstract void applicationDidDestroyed();
/**
* The method be called when the application enter background. But when the
* device screen off,this method will not invoked.
*/
protected abstract void applicationDidEnterBackground();
/**
* The method be called when the application enter foreground.
*/
protected abstract void applicationWillEnterForeground();
}
Modifica 2: Quello che ho scritto sotto non funzionerà davvero. Google ha rifiutato un'app che include una chiamata a ActivityManager.getRunningTasks (). Dalla documentazione , è evidente che questa API è solo a scopo di debug e sviluppo. Aggiornerò questo post non appena avrò tempo di aggiornare il progetto GitHub di seguito con un nuovo schema che utilizza i timer ed è quasi altrettanto buono.
Modifica 1: ho scritto un post sul blog e ho creato un semplice repository GitHub per renderlo davvero facile.
La risposta accettata e quella più votata non sono entrambe l'approccio migliore. L'implementazione della risposta più votata di isApplicationBroughtToBackground () non gestisce la situazione in cui l'attività principale dell'applicazione sta cedendo a un'attività definita nella stessa applicazione, ma ha un pacchetto Java diverso. Ho trovato un modo per farlo che funzionerà in quel caso.
Chiamalo in onPause () e ti dirà se l'applicazione sta andando in background perché è stata avviata un'altra applicazione o l'utente ha premuto il pulsante Home.
public static boolean isApplicationBroughtToBackground(final Activity activity) {
ActivityManager activityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(1);
// Check the top Activity against the list of Activities contained in the Application's package.
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
try {
PackageInfo pi = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_ACTIVITIES);
for (ActivityInfo activityInfo : pi.activities) {
if(topActivity.getClassName().equals(activityInfo.name)) {
return false;
}
}
} catch( PackageManager.NameNotFoundException e) {
return false; // Never happens.
}
}
return true;
}
Risposta corretta qui
Crea una classe con il nome MyApp come di seguito:
public class MyApp implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {
private Context context;
public void setContext(Context context)
{
this.context = context;
}
private boolean isInBackground = false;
@Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
isInBackground = true;
Log.d("status = ","we are out");
}
}
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
if(isInBackground){
isInBackground = false;
Log.d("status = ","we are in");
}
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onConfigurationChanged(Configuration configuration) {
}
@Override
public void onLowMemory() {
}
}
Quindi, ovunque tu voglia (migliore prima attività avviata in app), aggiungi il codice qui sotto:
MyApp myApp = new MyApp();
registerComponentCallbacks(myApp);
getApplication().registerActivityLifecycleCallbacks(myApp);
Fatto! Ora quando l'app è in background, otteniamo il registro status : we are out
e quando andiamo nell'app, otteniamo il registrostatus : we are out
La mia soluzione è stata ispirata dalla risposta di @ d60402 e si basa anche su una finestra temporale, ma non usando Timer
:
public abstract class BaseActivity extends ActionBarActivity {
protected boolean wasInBackground = false;
@Override
protected void onStart() {
super.onStart();
wasInBackground = getApp().isInBackground;
getApp().isInBackground = false;
getApp().lastForegroundTransition = System.currentTimeMillis();
}
@Override
protected void onStop() {
super.onStop();
if( 1500 < System.currentTimeMillis() - getApp().lastForegroundTransition )
getApp().isInBackground = true;
}
protected SingletonApplication getApp(){
return (SingletonApplication)getApplication();
}
}
dove SingletonApplication
è un'estensione di Application
classe:
public class SingletonApplication extends Application {
public boolean isInBackground = false;
public long lastForegroundTransition = 0;
}
Lo stavo usando con Google Analytics EasyTracker e ha funzionato. Potrebbe essere esteso per fare ciò che cerchi usando un semplice numero intero.
public class MainApplication extends Application {
int isAppBackgrounded = 0;
@Override
public void onCreate() {
super.onCreate();
appBackgroundedDetector();
}
private void appBackgroundedDetector() {
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
EasyTracker.getInstance(MainApplication.this).activityStart(activity);
}
@Override
public void onActivityResumed(Activity activity) {
isAppBackgrounded++;
if (isAppBackgrounded > 0) {
// Do something here
}
}
@Override
public void onActivityPaused(Activity activity) {
isAppBackgrounded--;
}
@Override
public void onActivityStopped(Activity activity) {
EasyTracker.getInstance(MainApplication.this).activityStop(activity);
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
});
}
}
so che è un po 'tardi ma penso che tutte queste risposte abbiano dei problemi mentre l'ho fatto come sotto e che funziona perfettamente.
creare un callback del ciclo di vita delle attività in questo modo:
class ActivityLifeCycle implements ActivityLifecycleCallbacks{
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
}
Activity lastActivity;
@Override
public void onActivityResumed(Activity activity) {
//if (null == lastActivity || (activity != null && activity == lastActivity)) //use this condition instead if you want to be informed also when app has been killed or started for the first time
if (activity != null && activity == lastActivity)
{
Toast.makeText(MyApp.this, "NOW!", Toast.LENGTH_LONG).show();
}
lastActivity = activity;
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
}
e registralo sulla tua classe di applicazione come di seguito:
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifeCycle());
}
Questa sembra essere una delle domande più complicate in Android poiché (al momento della stesura di questo documento) Android non ha equivalenti iOS applicationDidEnterBackground()
o applicationWillEnterForeground()
callback. Ho usato una libreria AppState che è stata messa insieme da @jenzz .
[AppState è] una libreria Android semplice e reattiva basata su RxJava che monitora le modifiche allo stato delle app. Notifica agli abbonati ogni volta che l'app passa in background e torna in primo piano.
Si è scoperto che questo è esattamente ciò di cui avevo bisogno, soprattutto perché la mia app aveva più attività, quindi il semplice controllo onStart()
o onStop()
un'attività non lo avrebbe tagliato.
Per prima cosa ho aggiunto queste dipendenze a Gradle:
dependencies {
compile 'com.jenzz.appstate:appstate:3.0.1'
compile 'com.jenzz.appstate:adapter-rxjava2:3.0.1'
}
Quindi è stata una semplice questione di aggiungere queste righe in una posizione appropriata nel tuo codice:
//Note that this uses RxJava 2.x adapter. Check the referenced github site for other ways of using observable
Observable<AppState> appState = RxAppStateMonitor.monitor(myApplication);
//where myApplication is a subclass of android.app.Application
appState.subscribe(new Consumer<AppState>() {
@Override
public void accept(@io.reactivex.annotations.NonNull AppState appState) throws Exception {
switch (appState) {
case FOREGROUND:
Log.i("info","App entered foreground");
break;
case BACKGROUND:
Log.i("info","App entered background");
break;
}
}
});
A seconda di come ti iscrivi all'osservabile, potresti dover annullare l'iscrizione per evitare perdite di memoria. Ancora una volta maggiori informazioni sulla pagina di github .
Questa è la versione modificata della risposta di @ d60402: https://stackoverflow.com/a/15573121/4747587
Fai tutto quanto menzionato lì. Ma invece di avere un Base Activity
e renderlo come genitore per ogni attività e la sostituzione di onResume()
e onPause
, fai quanto segue:
Nella tua classe di applicazione, aggiungi la riga:
registerActivityLifecycleCallbacks (callback Application.ActivityLifecycleCallbacks);
Questo callback
ha tutti i metodi del ciclo di vita delle attività e ora puoi sovrascrivere onActivityResumed()
e onActivityPaused()
.
Dai un'occhiata a questo Gist: https://gist.github.com/thsaravana/1fa576b6af9fc8fff20acfb2ac79fa1b
Puoi farlo facilmente con l'aiuto di ActivityLifecycleCallbacks
e ComponentCallbacks2
qualcosa di simile di seguito.
Crea una classe AppLifeCycleHandler
implementando sopra dette interfacce.
package com.sample.app;
import android.app.Activity;
import android.app.Application;
import android.content.ComponentCallbacks2;
import android.content.res.Configuration;
import android.os.Bundle;
/**
* Created by Naveen on 17/04/18
*/
public class AppLifeCycleHandler
implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {
AppLifeCycleCallback appLifeCycleCallback;
boolean appInForeground;
public AppLifeCycleHandler(AppLifeCycleCallback appLifeCycleCallback) {
this.appLifeCycleCallback = appLifeCycleCallback;
}
@Override
public void onActivityResumed(Activity activity) {
if (!appInForeground) {
appInForeground = true;
appLifeCycleCallback.onAppForeground();
}
}
@Override
public void onTrimMemory(int i) {
if (i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
appInForeground = false;
appLifeCycleCallback.onAppBackground();
}
}
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onConfigurationChanged(Configuration configuration) {
}
@Override
public void onLowMemory() {
}
interface AppLifeCycleCallback {
void onAppBackground();
void onAppForeground();
}
}
Nella tua classe che estende Application
implementa AppLifeCycleCallback
per ottenere i callback quando l'app passa tra primo piano e sfondo. Qualcosa come sotto.
public class BaseApplication extends Application implements AppLifeCycleHandler.AppLifeCycleCallback{
@Override
public void onCreate() {
super.onCreate();
AppLifeCycleHandler appLifeCycleHandler = new AppLifeCycleHandler(this);
registerActivityLifecycleCallbacks(appLifeCycleHandler);
registerComponentCallbacks(appLifeCycleHandler);
}
@Override
public void onAppBackground() {
Log.d("LifecycleEvent", "onAppBackground");
}
@Override
public void onAppForeground() {
Log.d("LifecycleEvent", "onAppForeground");
}
}
Spero che sia di aiuto.
MODIFICA In alternativa è ora possibile utilizzare il componente di architettura sensibile al ciclo di vita.
Dato che non ho trovato alcun approccio, che gestisca anche la rotazione senza controllare i timestamp, ho pensato di condividere anche come lo facciamo ora nella nostra app. L'unica aggiunta a questa risposta https://stackoverflow.com/a/42679191/5119746 è che prendiamo in considerazione anche l'orientamento.
class MyApplication : Application(), Application.ActivityLifecycleCallbacks {
// Members
private var mAppIsInBackground = false
private var mCurrentOrientation: Int? = null
private var mOrientationWasChanged = false
private var mResumed = 0
private var mPaused = 0
Quindi, per i callback abbiamo prima il curriculum:
// ActivityLifecycleCallbacks
override fun onActivityResumed(activity: Activity?) {
mResumed++
if (mAppIsInBackground) {
// !!! App came from background !!! Insert code
mAppIsInBackground = false
}
mOrientationWasChanged = false
}
E onActivityStopped:
override fun onActivityStopped(activity: Activity?) {
if (mResumed == mPaused && !mOrientationWasChanged) {
// !!! App moved to background !!! Insert code
mAppIsInBackground = true
}
E poi, ecco l'aggiunta: Verifica dei cambiamenti di orientamento:
override fun onConfigurationChanged(newConfig: Configuration) {
if (newConfig.orientation != mCurrentOrientation) {
mCurrentOrientation = newConfig.orientation
mOrientationWasChanged = true
}
super.onConfigurationChanged(newConfig)
}
Questo è tutto. Spero che questo aiuti qualcuno :)
Possiamo espandere questa soluzione usando LiveData
:
class AppForegroundStateLiveData : LiveData<AppForegroundStateLiveData.State>() {
private var lifecycleListener: LifecycleObserver? = null
override fun onActive() {
super.onActive()
lifecycleListener = AppLifecycleListener().also {
ProcessLifecycleOwner.get().lifecycle.addObserver(it)
}
}
override fun onInactive() {
super.onInactive()
lifecycleListener?.let {
this.lifecycleListener = null
ProcessLifecycleOwner.get().lifecycle.removeObserver(it)
}
}
internal inner class AppLifecycleListener : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onMoveToForeground() {
value = State.FOREGROUND
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onMoveToBackground() {
value = State.BACKGROUND
}
}
enum class State {
FOREGROUND, BACKGROUND
}
}
Ora possiamo iscriverci a questo LiveData e catturare gli eventi necessari. Per esempio:
appForegroundStateLiveData.observeForever { state ->
when(state) {
AppForegroundStateLiveData.State.FOREGROUND -> { /* app move to foreground */ }
AppForegroundStateLiveData.State.BACKGROUND -> { /* app move to background */ }
}
}
Queste risposte non sembrano corrette. Questi metodi vengono anche chiamati quando un'altra attività inizia e finisce. Quello che puoi fare è mantenere una bandiera globale (sì, i globi sono cattivi :) e impostarlo su true ogni volta che inizi una nuova attività. Impostalo su false nell'onCreate di ogni attività. Quindi, in onPause, controlli questa bandiera. Se è falso, l'app sta andando in background o viene uccisa.