Comment détecter quand une application Android va à l'arrière plan et revenir au premier plan

J'essaie d'écrire une application qui fait quelque chose de spécifique quand elle est ramenée au premier plan après un certain temps. Existe-t-il un moyen de détecter lorsqu'une application est envoyée en arrière-plan ou mise au premier plan?

318
demandé sur Peter Mortensen 2010-12-11 02:22:40

30 réponses

Les méthodes onPause() et onResume() sont appelées lorsque l'application est ramenée à l'arrière-plan et au premier plan. Cependant, ils sont également appelés lorsque l'application est démarrée pour la première fois, et avant qu'il soit tué. Vous pouvez en savoir plus dans Activité.

Il N'y a pas d'approche directe pour obtenir le statut de l'application en arrière-plan ou au premier plan, mais même j'ai fait face à ce problème et trouvé la solution avec onWindowFocusChanged et onStop.

Pour plus détails vérifier ici Android: Solution pour détecter quand une application Android va à l'arrière-plan et revenir au premier plan sans getRunningTasks ou getRunningAppProcesses.

83
répondu Girish Nair 2014-02-21 10:33:45

Voici comment j'ai réussi à résoudre ce problème. Cela fonctionne sur le principe que l'utilisation d'une référence temporelle entre les transitions d'activité fournira probablement des preuves suffisantes qu'une application a été "background" ou non.

Tout d'abord, j'ai utilisé un androïde.App.Instance d'Application (appelons-la MyApplication) qui a une minuterie, une TimerTask, une constante pour représenter le nombre maximum de millisecondes que la transition d'une activité à une autre pourrait raisonnablement prendre (je suis allé avec une valeur de 2s), et un booléen pour indiquer si oui ou non l'application était "en arrière-plan":

public class MyApplication extends Application {

    private Timer mActivityTransitionTimer;
    private TimerTask mActivityTransitionTimerTask;
    public boolean wasInBackground;
    private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000;
    ...

L'application fournit également deux méthodes pour démarrer et arrêter la minuterie / tâche:

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

Le dernier élément de cette solution consiste à ajouter un appel à chacune de ces méthodes à partir des événements onResume() et onPause() de toutes les activités ou, de préférence, dans une activité de base à partir de laquelle toutes vos activités concrètes héritent:

@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();
}

Donc, dans le cas où l'utilisateur navigue simplement entre le activités de votre application, l'onPause () de l'activité au départ démarre la minuterie, mais presque immédiatement la nouvelle activité entrée annule la minuterie avant qu'elle puisse atteindre le temps de transition maximum. Et donc, wasInBackground est false.

D'autre part, lorsqu'une activité vient au premier plan du lanceur, réveil de l'appareil, fin d'appel téléphonique, etc., plus que probablement la tâche de minuterie exécutée avant cet événement, et donc wasInBackground a été définie sur vrai .

170
répondu d60402 2013-03-22 14:42:01

2018: Android prend en charge ce nativement à travers les composants du cycle de vie.

Mise à jour de mars 2018: Il y a maintenant une meilleure solution. Voir ProcessLifecycleOwner . Vous devrez utiliser les nouveaux composants d'architecture 1.1.0 (les plus récents en ce moment) mais c'est spécifiquement conçu pour ce faire.

Il y a un simple échantillon dans cette réponse, mais j'ai écrit un exemple d'application et a blog à ce sujet.

Depuis J'ai écrit cela en 2014, différentes solutions sont apparues. Certains ont travaillé, certains ont été pensé à travailler , mais avaient des défauts (y compris le mien!) et nous, en tant que communauté (Android) appris à vivre avec les conséquences et a écrit des solutions de contournement pour les cas particuliers.

Ne supposez jamais qu'un seul extrait de code est la solution que vous recherchez, c'est peu probable; mieux encore, essayez de comprendre ce qu'il fait et pourquoi il le fait.

La classe MemoryBoss n'a jamais été réellement utilisée par moi comme écrit ici, c'était juste un morceau de pseudo-code qui fonctionnait.

À moins qu'il n'y ait une raison valable de ne pas utiliser les nouveaux composants d'architecture (et il y en a, surtout si vous ciblez de super anciennes API), alors allez-y et utilisez-les. Ils sont loin d'être parfaits, mais aucun n'était ComponentCallbacks2.

UPDATE / NOTES (novembre 2015) : People a fait deux Commentaires, le premier est que >= devrait être utilisé au lieu de == parce que la documentation indique que vous ne devrait pas vérifier les valeurs exactes . C'est bien pour la plupart des cas, mais gardez à l'esprit que si vous seulement vous souciez de faire quelque chose lorsque l'application est passée en arrière-plan, vous devrez utiliser == et le combiner également avec une autre solution (comme les rappels de cycle de vie D'activité), ou vous ne L'exemple (et cela m'est arrivé) est que si vous voulez verrouiller votre application avec un écran de mot de passe quand il va à la contexte (comme 1Password si vous le connaissez), vous pouvez accidentellement verrouiller votre application si vous manquez de mémoire et que vous testez soudainement >= TRIM_MEMORY, Car Android déclenchera un appel LOW MEMORY et c'est plus élevé que le vôtre. Alors soyez prudent comment / ce que vous testez.

De plus, certaines personnes ont demandé comment détecter quand vous revenez.

La façon la plus simple à laquelle je peux penser est expliquée ci-dessous, mais comme certaines personnes ne le connaissent pas, j'ajoute du pseudo-code à droite ici. En supposant que vous avez YourApplication et les classes MemoryBoss, dans votre class BaseActivity extends Activity (vous devrez en créer une si vous n'en avez pas).

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

Je recommande onStart parce que les boîtes de dialogue peuvent mettre en pause une activité, donc je parie que vous ne voulez pas que votre application pense "il est allé à l'arrière-plan" si tout ce que vous avez fait était d'afficher une boîte de dialogue en plein écran, mais votre kilométrage peut varier.

Et c'est tout. Le code dans le bloc if ne sera exécuté qu'une seule fois, même si vous allez à une autre activité, la nouvelle (qui aussi extends BaseActivity) rapportera wasInBackground est false donc il n'exécutera pas le code, jusqu'à ce que onMemoryTrimmed soit appelé et que l'indicateur soit à nouveau défini sur true.

J'espère que ça aide.

UPDATE / NOTES (avril 2015) : Avant de tout copier et coller sur ce code, notez que j'ai trouvé quelques cas où il peut ne pas être fiable à 100% et doit être combiné avec d'autres méthodes pour obtenir les meilleurs résultats. En particulier, il y a deux cas connus où le onTrimMemory le rappel n'est pas garanti pour être exécuté:

  1. Si votre téléphone verrouille l'écran pendant que votre application est visible (disons que votre appareil se verrouille après nn minutes), ce rappel n'est pas appelé (ou pas toujours) parce que le lockscreen est juste au-dessus, mais votre application est toujours "en cours d'exécution" bien que couvert.

  2. Si votre appareil est relativement faible en mémoire( et sous stress mémoire), le système d'exploitation semble ignorer cet appel et aller directement à plus critique niveau.

Maintenant, selon l'importance pour vous de savoir quand votre application est passée en arrière-plan, vous pouvez ou non avoir besoin d'étendre cette solution tout en gardant une trace du cycle de vie de l'activité et autres joyeusetés.

Gardez simplement à l'esprit ce qui précède et ayez une bonne équipe QA;)

FIN DE LA MISE À JOUR

Il est peut-être tard, mais il existe une méthode fiable dans Ice Cream Sandwich (API 14) et au-dessus de.

S'avère que lorsque votre l'application n'a plus D'interface utilisateur visible, un rappel est déclenché. Le rappel, que vous pouvez implémenter dans une classe personnalisée, s'appelle ComponentCallbacks2 (oui, avec un deux). Ce rappel est uniquement disponible {[34] } dans le niveau API 14 (Sandwich à la crème glacée) et au-dessus.

Vous obtenez essentiellement un appel à la méthode:

public abstract void onTrimMemory (int level)

Le niveau est de 20 ou plus précisément

public static final int TRIM_MEMORY_UI_HIDDEN

J'ai testé cela et cela fonctionne toujours, car le niveau 20 n'est qu'une "suggestion" que vous pourriez vous souhaitez libérer des ressources car votre application n'est plus visible.

Pour citer les documents officiels:

Niveau pour onTrimMemory (int): le processus avait montré une interface utilisateur, et ne le fait plus. Des allocations importantes avec L'interface utilisateur doivent être libérées à ce stade pour permettre une meilleure gestion de la mémoire.

Bien sûr, vous devriez implémenter ceci pour faire réellement ce qu'il dit (purger la mémoire qui n'a pas été utilisée dans un certain temps, effacer certaines collections qui ont été assis inutilisés, etc. Les possibilités sont infinies (voir les docs officiels pour d'autres niveaux possibles plus critiques).

Mais, ce qui est intéressant, c'est que le système d'exploitation vous dit: Hé, votre application est passée à l'arrière-plan!

Ce qui est exactement ce que vous vouliez savoir en premier lieu.

Comment déterminez-vous quand vous êtes revenu?

Eh bien, c'est facile, je suis sûr que vous avez une "BaseActivity" donc vous pouvez utiliser votre onResume () pour marquer le fait que vous êtes de retour. Parce que la seule fois où vous direz que vous n'êtes pas de retour est lorsque vous recevez un appel à la méthode onTrimMemory ci-dessus.

Ça marche. Vous n'avez pas obtenir de faux positifs. Si une activité reprend, vous êtes de retour, 100% des fois. Si l'utilisateur retourne à l'arrière, vous obtenez un autre appel onTrimMemory().

Vous devez vous inscrire à vos activités (ou mieux encore, une classe personnalisée).

Le moyen le plus simple de garantir que vous recevez toujours ceci est de créer un classe simple comme ceci:

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

Pour l'utiliser, dans votre implémentation D'Application ( vous en avez un, non?), faites quelque chose comme:

MemoryBoss mMemoryBoss;
@Override
public void onCreate() {
   super.onCreate();
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
      mMemoryBoss = new MemoryBoss();
      registerComponentCallbacks(mMemoryBoss);
   } 
}

Si vous créez un Interface Vous pouvez ajouter un else à ce if et implémenter ComponentCallbacks (sans le 2) utilisé dans tout ce qui est inférieur à L'API 14. Ce rappel a seulement la méthode onLowMemory() et n'est pas appelé quand vous allez à l'arrière-plan, mais vous devriez l'utiliser pour couper la mémoire.

Lancez maintenant votre application et appuyez sur maison. Votre méthode onTrimMemory(final int level) doit être appelée (astuce: ajouter la journalisation).

La dernière étape consiste à se désinscrire du rappel. Probablement le meilleur endroit est le onTerminate() méthode de votre Application, , mais, cette méthode n'est pas appelée sur un périphérique réel:

/**
 * 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.
 */

Donc, sauf si vous avez vraiment une situation où vous ne voulez plus être enregistré, vous pouvez l'ignorer en toute sécurité, puisque votre processus est en train de mourir au niveau du système d'exploitation de toute façon.

Si vous décidez de vous désinscrire à un moment donné (si vous, par exemple, fournissez un mécanisme d'arrêt pour que votre application puisse nettoyer et mourir), vous pouvez faire:

unregisterComponentCallbacks(mMemoryBoss);

Et c'est tout.

146
répondu Martin Marconcini 2018-04-19 16:24:44

Edit: les nouveaux composants de l'architecture ont apporté quelque chose de prometteur: ProcessLifecycleOwner , voir la réponse de @ vokilam


La solution réelle selon un Google I/O parlez - :

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

}

Oui. Je sais qu'il est difficile de croire que cette solution simple fonctionne puisque nous avons tellement de solutions étranges ici.

Mais il y a de l'espoir.

116
répondu Thiago Porciúncula 2017-09-27 18:48:37

Basé sur Martín Marconcinis réponse (merci!) J'ai finalement trouvé une solution fiable (et très simple).

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

Ajoutez ensuite ceci à votre onCreate() de votre classe D'Application

public class MyApp extends android.app.Application {

    @Override
    public void onCreate() {
        super.onCreate();

        ApplicationLifeCycleHandler handler = new ApplicationLifeCycleHandler();
        registerActivityLifecycleCallbacks(handler);
        registerComponentCallbacks(handler);

    }

}
61
répondu rickul 2015-09-07 12:00:54

ProcessLifecycleOwner semble être une solution prometteuse aussi.

ProcessLifecycleOwner enverra ON_START, ON_RESUME événements, comme une première activité se déplace à travers ces événements. ON_PAUSE, ON_STOP, les événements seront expédiés avec un délai après qu'une dernière activité les aura traversés. Ce délai est suffisamment long pour garantir que ProcessLifecycleOwner n'enverra aucun événement si les activités sont détruites et recréées en raison d'un changement de configuration.

Une implémentation peut être aussi simple comme

public class AppLifecycleListener implements LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onMoveToForeground() {
        // app moved to foreground
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void onMoveToBackground() {
       // app moved to background
    }
}

// register observer
ProcessLifecycleOwner.get().getLifecycle().addObserver(new AppLifecycleListener());

Selon le code source, la valeur de retard actuelle est 700ms.

58
répondu vokilam 2017-06-09 15:29:21

Nous utilisons cette méthode. Il semble trop simple à travailler, mais il a été bien testé dans notre application et fonctionne en fait étonnamment bien dans tous les cas, y compris aller à l'écran d'accueil par le bouton "Accueil", par le bouton "retour", Ou après le verrouillage de l'écran. Lui donner un essai.

L'idée est, quand au premier plan, Android commence toujours une nouvelle activité juste avant d'arrêter la précédente. Ce n'est pas garanti, mais c'est comme ça que ça marche. BTW, Flurry semble utiliser la même logique (juste une supposition, Je n'ai pas vérifié cela, mais il accroche à les mêmes événements).

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

}

Edit: selon les commentaires, nous avons également déménagé à onStart () dans les versions ultérieures du code. En outre, j'ajoute des super appels, qui manquaient à mon message initial, parce que c'était plus un concept qu'un code de travail.

57
répondu Nick Frolov 2017-02-17 16:32:58

Si votre application se compose de plusieurs activités et / ou d'activités empilées comme un widget de barre d'onglets, la substitution de onPause () et onResume () ne fonctionnera pas. C'est-à-dire que lors du démarrage d'une nouvelle activité, les activités en cours seront interrompues avant la création de la nouvelle activité. La même chose s'applique lors de la finition (en utilisant le bouton "Retour") d'une activité.

J'ai trouvé deux méthodes qui semblent fonctionner comme voulu.

Le premier nécessite L'autorisation GET_TASKS et consiste en une méthode simple qui vérifie si le top l'activité en cours d'exécution sur le périphérique appartient à l'application, en comparant les noms de paquets:

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

Cette méthode a été trouvée dans le cadre Droid-Fu (maintenant appelé allumage).

La deuxième méthode que j'ai implémentée ne nécessite pas L'autorisation GET_TASKS, ce qui est bon. Au lieu de cela, il est un peu plus compliqué à mettre en œuvre.

Dans votre classe MainApplication, vous avez une variable qui suit le nombre d'activités en cours d'exécution dans votre application. Dans onResume () pour chaque activity vous augmentez la variable et dans onPause () vous la diminuez.

Lorsque le nombre d'activités en cours atteint 0, l'application est mise en arrière-plan si les conditions suivantes sont vraies:

  • l'activité en pause n'est pas terminée (le bouton "Retour" a été utilisé). Cela peut être fait en utilisant l'activité de la méthode.isFinishing ()
  • une nouvelle activité (même nom de paquet) n'est pas en cours de démarrage. Vous pouvez remplacer la méthode startActivity() pour définir une variable indique cela, puis réinitialisez-le dans onPostResume(), qui est la dernière méthode à exécuter lorsqu'une activité est créée / reprise.

Lorsque vous pouvez détecter que l'application a démissionné à l'arrière-plan, il est facile de détecter quand il est ramené au premier plan ainsi.

54
répondu Emil 2012-03-26 17:19:18

Créez une classe qui s'étend sur Application. Ensuite, nous pouvons utiliser sa méthode override, onTrimMemory().

Pour détecter si l'application est passée en arrière-plan, nous utiliserons:

 @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
        }
    }
31
répondu Harpreet 2018-03-26 14:02:33

Pensez à utiliser onUserLeaveHint. Cela ne sera appelé que lorsque votre application passe en arrière-plan. onPause aura des cas de coin à gérer, car il peut être appelé pour d'autres raisons; par exemple, si l'utilisateur ouvre une autre activité dans votre application telle que votre page de paramètres, la méthode onPause de votre activité principale sera appelée même si elle est toujours dans votre application; le suivi de ce qui se passe entraînera des bugs lorsque vous demander.

Quand on UserLeaveHint est appelé, vous pouvez définir un indicateur booléen inBackground sur true. Lorsque onResume est appelé, supposez seulement que vous êtes revenu au premier plan si l'indicateur inBackground est défini. C'est parce que onResume sera également appelée sur votre activité principale, si l'utilisateur était juste dans votre menu des paramètres, et n'a jamais quitté l'application.

Rappelez-vous que si l'utilisateur appuie sur le bouton d'accueil alors que dans votre écran Paramètres, onUserLeaveHint sera appelé dans votre activité paramètres, et quand ils retournent onResume sera appelé dans votre activité paramètres. Si vous n'avez que ce code de détection dans votre activité principale, vous manquerez ce cas d'utilisation. Pour avoir ce code dans toutes vos activités sans dupliquer le code, ayez une classe d'activité abstraite qui étend L'activité, et mettez votre code commun dedans. Ensuite, chaque activité que vous avez peut étendre cette activité abstraite.

Par exemple:

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 {
    ...
}
16
répondu OldSchool4664 2012-09-20 23:23:57

ActivityLifecycleCallbacks peut être intéressant, mais il n'est pas bien documenté.

Cependant, si vous appelez registerActivityLifecycleCallbacks () vous devriez être capable d'obtenir des rappels lorsque des activités sont créées, détruites, etc. Vous pouvez appeler getComponentName() pour l'Activité.

12
répondu Reno 2014-02-07 19:55:13

Dans votre Application, ajoutez le rappel et vérifiez l'activité racine d'une manière comme ceci:

@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();
            }
        }
    });
}
7
répondu Cynichniy Bandera 2015-02-25 16:09:48

, j'ai créé un projet sur Github app-au premier plan-arrière-plan-écoutez

Créez une BaseActivity pour toutes les activités de votre application.

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

Maintenant, utilisez cette BaseActivity comme une super classe de toute votre activité comme MainActivity étend BaseActivity et onAppStart sera appelé lorsque vous démarrez votre application et onAppPause () sera appelé lorsque l'application passe en arrière-plan de n'importe quel écran.

6
répondu kiran boghra 2016-06-11 19:47:17

C'est assez facile avec ProcessLifecycleOwner

Ajouter ces dépendances

implementation "android.arch.lifecycle:extensions:$project.archLifecycleVersion"
kapt "android.arch.lifecycle:compiler:$project.archLifecycleVersion"

Dans 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")
    }
}

Puis dans votre activité de base:

override fun onCreate() {
        super.onCreate()

        ProcessLifecycleOwner.get()
                .lifecycle
                .addObserver(
                        ForegroundBackgroundListener()
                                .also { appObserver = it })
    }

Voir mon article sur ce sujet: https://medium.com/@egek92/how-to-actually-detect-foreground-background-changes-in-your-android-application-without-wanting-9719cc822c48

5
répondu Ege Kuzubasioglu 2018-01-31 10:27:40

J'ai trouvé une bonne méthode pour détecter l'application si entrer au premier plan ou en arrière-plan. Voici mon code . Espérons que cette aide vous.

/**
 * 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();

}

3
répondu Folyd 2015-11-12 11:21:45

Edit 2: ce que j'ai écrit ci-dessous ne fonctionnera pas réellement. Google a rejeté une application qui inclut un appel à ActivityManager.getRunningTasks (). À partir de la documentation , il est évident que cette API est uniquement destinée au débogage et au développement. Je mettrai à jour ce post dès que j'aurai le temps de mettre à jour le projet GitHub ci-dessous avec un nouveau schéma qui utilise des minuteries et est presque aussi bon.

Edit 1: j'ai écrit un blog et créé un simple GitHub repository pour rendre cela vraiment facile.

La réponse acceptée et la mieux notée ne sont pas vraiment la meilleure approche. L'implémentation de la réponse la mieux notée de isApplicationBroughtToBackground() ne gère pas la situation où L'activité principale de l'Application cède à une activité définie dans la même Application, mais elle a un package Java différent. Je suis venu avec un moyen de le faire qui fonctionnera dans ce cas.

Appelez ceci dans onPause (), et il vous dira si votre application passe en arrière-plan parce qu'une autre application a démarré ou que l'Utilisateur a appuyé sur le bouton d'accueil.

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;
}
3
répondu Sky Kelsey 2016-06-11 19:39:23

Vous pouvez utiliser:

Nul protégé onRestart ()

Pour différer entre les nouveaux démarrages et les redémarrages.

entrez la description de l'image ici

2
répondu AYBABTU 2016-03-09 14:11:33

Ma solution a été inspirée par la réponse de @d60402 et repose également sur une fenêtre temporelle, mais sans utiliser le 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();
  }
}

Où le {[3] } est une extension de la classe Application:

public class SingletonApplication extends Application {
  public boolean isInBackground = false;
  public long lastForegroundTransition = 0;
}
1
répondu injecteer 2015-05-08 11:12:30

Je l'utilisais avec Google Analytics EasyTracker, et cela a fonctionné. Il pourrait être étendu pour faire ce que vous cherchez en utilisant un entier simple.

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

            }
        });
    }
}
1
répondu Bill Mote 2016-06-11 19:42:47

Je sais que c'est un peu tard mais je pense que toutes ces réponses ont quelques problèmes alors que je l'ai fait comme ci-dessous et cela fonctionne parfaitement.

Créez un rappel de cycle de vie d'activité comme ceci:

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

    }
}

Et enregistrez-le simplement sur votre classe d'application comme ci-dessous:

public class MyApp extends Application {

@Override
public void onCreate() {
    super.onCreate();
    registerActivityLifecycleCallbacks(new ActivityLifeCycle());
}
1
répondu Amir Ziarati 2017-05-15 04:03:21

C'est la version modifiée de @d60402 réponse: https://stackoverflow.com/a/15573121/4747587

Faites tout ce qui y est mentionné. Mais au lieu d'avoir un Base Activity et de le faire en tant que parent pour chaque activité et de remplacer les onResume() et onPause, Faites ce qui suit:

Dans votre classe d'application, ajoutez la ligne:

RegisterActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks de rappel);

CE callback a toutes les méthodes de cycle de vie d'activité et vous pouvez maintenant remplacer onActivityResumed() et onActivityPaused().

Jetez un oeil à cet essentiel: https://gist.github.com/thsaravana/1fa576b6af9fc8fff20acfb2ac79fa1b

1
répondu Henry 2018-01-09 06:39:43

Ce que j'ai fait est de m'assurer que toutes les activités in-app sont lancées avec {[1] } puis de vérifier si onActivityResult a été appelé avant onResume. Si ce n'était pas le cas, cela signifie que nous venons de revenir de quelque part en dehors de notre application.

boolean onActivityResultCalledBeforeOnResume;

@Override
public void startActivity(Intent intent) {
    startActivityForResult(intent, 0);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);
    onActivityResultCalledBeforeOnResume = true;
}

@Override
protected void onResume() {
    super.onResume();
    if (!onActivityResultCalledBeforeOnResume) {
        // here, app was brought to foreground
    }
    onActivityResultCalledBeforeOnResume = false;
}
0
répondu arturh 2012-07-15 02:17:44

C'est ma solution https://github.com/doridori/AndroidUtils/blob/master/App/src/main/java/com/doridori/lib/app/ActivityCounter.java

Fondamentalement impliqué compter les méthodes de cycle de vie pour toutes les activités avec une minuterie pour attraper les cas où il n'y a pas d'activité actuellement au premier plan mais l'application est (c'est-à-dire en rotation)

0
répondu Dori 2014-11-21 14:26:19

Voici ma solution. Enregistrez simplement cette ActivityLifecycleCallbacks dans votre classe D'Application principale. Dans les commentaires, je mentionne un cas D'activité de profil utilisateur. Cette activité est simplement une avec des bords transparents.

/**
 * This class used Activity lifecycle callbacks to determine when the application goes to the
 * background as well as when it is brought to the foreground.
 */
public class Foreground implements Application.ActivityLifecycleCallbacks
{
    /**
     * How long to wait before checking onStart()/onStop() count to determine if the app has been
     * backgrounded.
     */
    public static final long BACKGROUND_CHECK_DELAY_MS = 500;

    private static Foreground sInstance;

    private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
    private boolean mIsForeground = false;
    private int mCount;

    public static void init(final Application application)
    {
        if (sInstance == null)
        {
            sInstance = new Foreground();
            application.registerActivityLifecycleCallbacks(sInstance);
        }
    }

    public static Foreground getInstance()
    {
        return sInstance;
    }

    public boolean isForeground()
    {
        return mIsForeground;
    }

    public boolean isBackground()
    {
        return !mIsForeground;
    }

    @Override
    public void onActivityStarted(final Activity activity)
    {
        mCount++;

        // Remove posted Runnables so any Meteor disconnect is cancelled if the user comes back to
        // the app before it runs.
        mMainThreadHandler.removeCallbacksAndMessages(null);

        if (!mIsForeground)
        {
            mIsForeground = true;
        }
    }

    @Override
    public void onActivityStopped(final Activity activity)
    {
        mCount--;

        // A transparent Activity like community user profile won't stop the Activity that launched
        // it. If you launch another Activity from the user profile or hit the Android home button,
        // there are two onStops(). One for the user profile and one for its parent. Remove any
        // posted Runnables so we don't get two session ended events.
        mMainThreadHandler.removeCallbacksAndMessages(null);
        mMainThreadHandler.postDelayed(new Runnable()
        {
            @Override
            public void run()
            {
                if (mCount == 0)
                {
                    mIsForeground = false;
                }
            }
        }, BACKGROUND_CHECK_DELAY_MS);
    }

    @Override
    public void onActivityCreated(final Activity activity, final Bundle savedInstanceState)
    {

    }

    @Override
    public void onActivityResumed(final Activity activity)
    {

    }

    @Override
    public void onActivityPaused(final Activity activity)
    {

    }

    @Override
    public void onActivitySaveInstanceState(final Activity activity, final Bundle outState)
    {

    }

    @Override
    public void onActivityDestroyed(final Activity activity)
    {

    }
}
0
répondu Stephen 2016-02-12 02:42:49

Mon application doit "redémarrer" après le retour de l'arrière-plan-montrer une série d'activités, selon les sollicitations des clients. Après une recherche approfondie sur la façon de gérer les transitions arrière-plan/premier plan (traitées très différemment entre iOS et Android), j'ai croisé cette question. Trouvé une aide très utile ici, spécialement de la réponse la plus votée et celle signalée comme correcte. Cependant, il suffit de réinstantier l'activité racine chaque fois que l'application entre au premier plan semblait trop ennuyeux, lorsque vous pensez à UX. La solution qui a fonctionné pour moi, et celle que je pense la plus adéquate - basée sur la fonctionnalité des applications Youtube et Twitter - était de combiner les réponses de @ GirishNair et @d60402: appeler la minuterie lorsque la mémoire de coupe de l'application, comme suit:

@Override
public void onTrimMemory(int level) {
    if (stateOfLifeCycle.equals("Stop")) {
        startActivityTransitionTimer();
    }

    super.onTrimMemory(level);
}

MA limite de minuterie est fixée à 30 secondes-je pense à augmenter un peu.

private final long MAX_ACTIVITY_TRANSITION_TIME = 30000;

Et lorsque l'application passe au premier plan, est relancée ou détruite, appelez la méthode pour annuler minuterie.

Sur l'extension de L'application:

@Override
public void onActivityCreated(Activity activity, Bundle arg1) {
    stopActivityTransitionTimer();
    stateOfLifeCycle = "Create";
}

@Override
public void onActivityDestroyed(Activity activity) {
    stopActivityTransitionTimer();
    stateOfLifeCycle = "Destroy";
}

Sur l'activité (de préférence sur une activité de base, héritée par les autres):

@Override
protected void onStart() {
    super.onStart();
    if (App.wasInBackground) {
        stopActivityTransitionTimer();
    }
}

Dans mon cas, lorsque l'application passe au premier plan après l'heure maximale, une nouvelle tâche est créée, de sorte que stopActivityTransitionTimer() est appelée onActivityCreated () ou onActivityDestroyed (), dans la classe d'extension app - ce qui rend inutile d'appeler la méthode dans une activité. Espérons que cela aide.

0
répondu Pablo 2016-05-04 13:06:20

Que diriez-vous de cette solution

public class BaseActivity extends Activity
{

    static String currentAct = "";

    @Override
    protected void onStart()
    {
        super.onStart();

        if (currentAct.equals(""))
            Toast.makeText(this, "Start", Toast.LENGTH_LONG).show();

        currentAct = getLocalClassName();
    }

    @Override
    protected void onStop()
    {
        super.onStop();

        if (currentAct.equals(getLocalClassName()))
        {
            currentAct = "";
            Toast.makeText(this, "Stop", Toast.LENGTH_LONG).show();
        }
    }
}

Toute activité doit étendre BaseActivity.

Lorsqu'une activité en appelle une autre (a - >B), currentAct n'est pas égal à getlocalclassname() car onStart() de la deuxième activité (B) est appelé avant onStop() du premier (a) ( https://developer.android.com/guide/components/activities.html#CoordinatingActivities).

Lorsque l'utilisateur appuie sur le bouton d'accueil ou le changement entre l'application va simplement appeler onStop () puis currentAct est égal à getLocalClassName ().

0
répondu Ismael 2017-03-10 02:06:51

Cela semble être l'une des questions les plus compliquées dans Android puisque (à ce jour) Android n'a pas d'équivalents iOS de applicationDidEnterBackground() ou applicationWillEnterForeground() callbacks. J'ai utilisé une bibliothèque AppState qui a été mise en place par @jenzz.

[AppState est] une bibliothèque Android simple et réactive basée sur RxJava qui surveille les changements d'état de l'application. Il avertit les abonnés chaque fois que l'application passe en arrière-plan et revient au premier plan.

Il s'est avéré c'est exactement ce dont j'avais besoin, surtout parce que mon application avait plusieurs activités, donc simplement vérifier onStart() ou onStop() sur une activité n'allait pas la couper.

J'ai d'abord ajouté ces dépendances à gradle:

dependencies {
    compile 'com.jenzz.appstate:appstate:3.0.1'
    compile 'com.jenzz.appstate:adapter-rxjava2:3.0.1'
}

Ensuite, il s'agissait simplement d'ajouter ces lignes à un endroit approprié dans votre code:

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

Selon la façon dont vous vous abonnez à l'observable, vous devrez peut-être vous désabonner pour éviter les fuites de mémoire. Encore plus d'informations sur la page github .

0
répondu Deniz 2017-09-22 20:05:28

En utilisant le code ci-dessous, je suis en mesure d'obtenir mon état de premier plan ou d'arrière-plan de l'application.

Pour plus de détails sur son fonctionnement, texte fort cliquez sur ici

import android.content.ComponentCallbacks2;
import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

private Context context;
private Toast toast;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    context = this;
}

private void showToast(String message) {
    //If toast is already showing cancel it
    if (toast != null) {
        toast.cancel();
    }

    toast = Toast.makeText(context, message, Toast.LENGTH_SHORT);
    toast.show();
}

@Override
protected void onStart() {
    super.onStart();
    showToast("App In Foreground");
}

@Override
public void onTrimMemory(int level) {
    super.onTrimMemory(level);
    if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
        showToast("App In Background");
    }
  }
}
0
répondu Jitendra Singh 2018-02-28 09:49:23

Créer une classe avec le nom MyApp comme ci-dessous:

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

    }
}

Ensuite, partout où vous voulez (meilleure première activité lancée dans l'application), ajoutez le code ci-dessous:

MyApp myApp = new MyApp();
registerComponentCallbacks(myApp);
getApplication().registerActivityLifecycleCallbacks(myApp);

Fait! Maintenant, lorsque l'application est en arrière-plan, on obtient log status : we are out et quand nous allons dans l'application, nous obtenons log status : we are out

0
répondu erfan 2018-03-15 06:08:43

Vous pouvez le faire facilement avec l'aide de ActivityLifecycleCallbacks et ComponentCallbacks2 quelque chose comme ci-dessous.

Créer une classe AppLifeCycleHandler implémentant au-dessus desdites interfaces.

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

Dans votre classe qui étend Application implémentez AppLifeCycleCallback pour obtenir les rappels lorsque l'application bascule entre le premier plan et l'arrière-plan. Quelque chose comme ci-dessous.

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

J'espère que cela aide.

Modifier Comme alternative, vous pouvez maintenant utiliser le composant d'architecture conscient du cycle de vie.

0
répondu Naveen T P 2018-04-17 13:07:53