NE PAS UTILISER CETTE RÉPONSE
La réponse de l'utilisateur1269737 est la façon correcte (approuvée par Google/Android) de procéder. . Allez lire leur réponse et donnez-leur un +1.
Je vais laisser ma réponse originale ici pour la postérité. C'était la meilleure disponible en 2012, mais maintenant Android a un support approprié pour cela.
Réponse originale
La clé est d'utiliser ActivityLifecycleCallbacks
(notez que cela nécessite le niveau 14 de l'API Android (Android 4.0)). Vérifiez simplement si le nombre d'activités arrêtées est égal au nombre d'activités lancées. S'ils sont égaux, votre application est en arrière-plan. S'il y a plus d'activités démarrées, votre application est toujours visible. S'il y a plus d'activités reprises que d'activités arrêtées, votre application est non seulement visible, mais elle est aussi au premier plan. Votre activité peut donc se trouver dans trois états principaux : visible et au premier plan, visible mais pas au premier plan, et non visible et pas au premier plan (c'est-à-dire en arrière-plan).
Ce qui est vraiment bien avec cette méthode, c'est qu'il n'y a pas de problèmes d'asynchronisme. getRunningTasks()
mais il n'est pas non plus nécessaire de modifier chaque Activity
dans votre application afin d'activer/désactiver quelque chose dans l'application onResumed()
/ onPaused()
. Il ne s'agit que de quelques lignes de code autonomes, qui fonctionnent dans l'ensemble de votre application. De plus, il n'est pas nécessaire d'obtenir des autorisations bizarres.
MyLifecycleHandler.java :
public class MyLifecycleHandler implements ActivityLifecycleCallbacks {
// I use four separate variables here. You can, of course, just use two and
// increment/decrement them instead of using four and incrementing them all.
private int resumed;
private int paused;
private int started;
private int stopped;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
++resumed;
}
@Override
public void onActivityPaused(Activity activity) {
++paused;
android.util.Log.w("test", "application is in foreground: " + (resumed > paused));
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityStarted(Activity activity) {
++started;
}
@Override
public void onActivityStopped(Activity activity) {
++stopped;
android.util.Log.w("test", "application is visible: " + (started > stopped));
}
// If you want a static function you can use to check if your application is
// foreground/background, you can use the following:
/*
// Replace the four variables above with these four
private static int resumed;
private static int paused;
private static int started;
private static int stopped;
// And these two public static functions
public static boolean isApplicationVisible() {
return started > stopped;
}
public static boolean isApplicationInForeground() {
return resumed > paused;
}
*/
}
MonApplication.java :
// Don't forget to add it to your manifest by doing
// <application android:name="your.package.MyApplication" ...
public class MyApplication extends Application {
@Override
public void onCreate() {
// Simply add the handler, and that's it! No need to add any code
// to every activity. Everything is contained in MyLifecycleHandler
// with just a few lines of code. Now *that's* nice.
registerActivityLifecycleCallbacks(new MyLifecycleHandler());
}
}
@Mewzer a posé de bonnes questions sur cette méthode, auxquelles j'aimerais répondre dans cette réponse pour tout le monde :
onStop()
n'est pas appelé dans les situations de faible mémoire ; est-ce un problème ici ?
Non. Les docs pour onStop()
dites :
Notez que cette méthode peut ne jamais être appelée, dans les situations de faible mémoire où le système n'a pas assez de mémoire pour maintenir le processus de votre activité en cours d'exécution après l'appel de sa méthode onPause().
La clé ici est de "garder votre activité processus en cours ..." Si cette situation de mémoire faible est atteinte, votre processus est tué (pas seulement votre activité). Cela signifie que cette méthode de vérification de l'arrière-plan est toujours valable car a) vous ne pouvez pas vérifier l'arrière-plan de toute façon si votre processus est tué, et b) si votre processus redémarre (parce qu'une nouvelle activité est créée), les variables membres (qu'elles soient statiques ou non) de l'élément MyLifecycleHandler
sera réinitialisé à 0
.
Cela fonctionne-t-il pour les changements de configuration ?
Par défaut, non. Vous devez explicitement définir configChanges=orientation|screensize
( |
avec tout ce que vous voulez) dans votre fichier manifeste et gérer les changements de configuration, sinon votre activité sera détruite et recréée. Si vous ne définissez pas cette option, les méthodes de votre activité seront appelées dans cet ordre : onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume
. Comme vous pouvez le constater, il n'y a pas de chevauchement (normalement, deux activités se chevauchent très brièvement lorsqu'on passe de l'une à l'autre, c'est ainsi que fonctionne cette méthode de détection de l'arrière-plan). Afin de contourner ce problème, vous devez définir configChanges
afin que votre activité ne soit pas détruite. Heureusement, je n'ai pas eu à mettre configChanges
déjà dans tous mes projets parce qu'il n'était pas souhaitable que toute mon activité soit détruite par la rotation/le redimensionnement de l'écran, donc je n'ai jamais trouvé que cela posait problème. (merci à dpimka de m'avoir rafraîchi la mémoire sur ce point et de m'avoir corrigé !)
Une note :
Lorsque j'ai dit "arrière-plan" dans cette réponse, je voulais dire "votre application n'est plus visible". Les activités Android peuvent être visibles mais ne pas être au premier plan (par exemple, s'il y a une superposition de notifications transparente). C'est pourquoi j'ai mis à jour cette réponse pour refléter cela.
Il est important de savoir qu'Android a un moment de limbo bizarre quand on change d'activité où rien n'est au premier plan . Pour cette raison, si vous vérifiez si votre application est au premier plan lorsque vous passez d'une activité à l'autre (dans la même application), on vous dira que vous n'êtes pas au premier plan (même si votre application est toujours l'application active et est visible).
Vous pouvez vérifier si votre application est au premier plan dans le fichier Activity
's onPause()
méthode après super.onPause()
. Rappelez-vous l'étrange état de limbes dont je viens de parler.
Vous pouvez vérifier si votre application est visible (c.-à-d. si elle n'est pas en arrière-plan) dans la page Activity
's onStop()
méthode après super.onStop()
.
3 votes
Duplicata possible de Comment déterminer si une de mes activités est au premier plan ?
11 votes
Je suis confus ici pourquoi Android ne peut pas fournir une simple surcharge de la classe d'application pour cela ? Est-ce trop difficile de savoir cela au niveau de la plateforme ? @Override protected void onApplicationSentToBackground() { }
2 votes
@ChuckD - ce serait logique, et c'est ce que le SDK Android semble éviter de faire parfois :/.
0 votes
codingaffairs.blogspot.com/2016/05/
2 votes
IOS est doté de cette fonctionnalité, je ne sais pas pourquoi Google rend la chose si difficile. C'est un besoin tellement évident.
0 votes
Pour moi, ce qui a fonctionné, c'est une mise en œuvre alternative. Avoir une activité et le reste de l'interface utilisateur sous forme de fragments. Ensuite, le
OnPause
yOnResume
les callbacks peuvent fonctionner0 votes
Allez voir la réponse de @user1269737. Ce devrait être la bonne réponse !
0 votes
La solution la plus récente/correcte est toujours loin derrière : stackoverflow.com/a/48767617/1680919
0 votes
Bien que cela fonctionne, il n'est pas nécessaire de l'implémenter vous-même. Google a déjà ajouté ProcessLifecycleOwner qui fait la même chose pour vous en utilisant LifecycleObserver. Consultez stackoverflow.com/a/52678290/6600000
0 votes
ProcessLifecycleOwner est la solution la plus récente