J'essaie d'écrire une application qui fait quelque chose de spécifique lorsqu'elle est remise 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?
J'essaie d'écrire une application qui fait quelque chose de spécifique lorsqu'elle est remise 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?
Réponses:
Les méthodes onPause()
et onResume()
sont appelées lorsque l'application est mise en arrière-plan et à nouveau au premier plan. Cependant, ils sont également appelés lorsque l'application est démarrée pour la première fois et avant d'être supprimée. Vous pouvez en savoir plus dans Activity .
Il n'y a pas d'approche directe pour obtenir l'état de l'application en arrière-plan ou au premier plan, mais même moi, j'ai rencontré ce problème et trouvé la solution avec onWindowFocusChanged
et onStop
.
Pour plus de détails, consultez ici Android: Solution pour détecter lorsqu'une application Android passe en arrière-plan et revenir au premier plan sans getRunningTasks ou getRunningAppProcesses .
MISE À JOUR DE MARS 2018 : Il y a maintenant une meilleure solution. Voir ProcessLifecycleOwner . Vous devrez utiliser les nouveaux composants de l'architecture 1.1.0 (les plus récents à l'heure actuelle), mais il est spécialement conçu pour cela.
Il y a un exemple simple fourni dans cette réponse, mais j'ai écrit un exemple d'application et un blog à ce sujet.
Depuis que j'ai écrit cela en 2014, différentes solutions sont apparues. Certains fonctionnaient, certains étaient censés fonctionner , mais avaient des défauts (y compris le mien!) Et nous, en tant que communauté (Android), avons appris à vivre avec les conséquences et avons écrit des solutions de contournement pour les cas spéciaux.
Ne présumez jamais qu'un seul extrait de code est la solution que vous recherchez, il est peu probable que ce soit le cas; mieux encore, essayez de comprendre ce qu'il fait et pourquoi il le fait.
La MemoryBoss
classe n'a jamais été 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 pour que vous n'utilisiez pas les nouveaux composants de l'architecture (et il y en a certains, surtout si vous ciblez de super vieux API), alors allez-y et utilisez-les. Ils sont loin d'être parfaits, mais aucun ne l'était ComponentCallbacks2
.
MISE À JOUR / NOTES (novembre 2015) : Les gens ont fait deux commentaires, le premier est que cela >=
devrait être utilisé au lieu de ==
parce que la documentation indique que vous ne devriez pas vérifier les valeurs exactes . C'est très bien dans la plupart des cas, mais gardez à l'esprit que si vous ne voulez faire quelque chose que lorsque l'application est passée en arrière-plan, vous devrez utiliser == et la combiner avec une autre solution (comme les rappels de cycle de vie d'activité), ou vous peut ne pas obtenir l'effet souhaité. L'exemple (et cela m'est arrivé) est que si vous voulez verrouillervotre application avec un écran de mot de passe en arrière-plan (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 LOW MEMORY
appel et c'est plus élevé que le vôtre. Soyez donc prudent comment / ce que vous testez.
De plus, certaines personnes ont demandé comment détecter quand vous revenez.
La manière la plus simple à laquelle je pense est expliquée ci-dessous, mais comme certaines personnes ne la connaissent pas, j'ajoute un pseudo-code ici. En supposant que vous avez YourApplication
et les MemoryBoss
classes, dans votre class BaseActivity extends Activity
(vous devrez en créer un 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 car Dialogs peut suspendre une activité, donc je parie que vous ne voulez pas que votre application pense "qu'elle est passée en 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 si vous ne sera exécutée une fois la nouvelle (qui a également, même si vous allez à une autre activité, extends BaseActivity
) fera rapport wasInBackground
est false
donc il ne sera pas exécuter le code, jusqu'à ce que l' onMemoryTrimmed
on appelle et le drapeau est défini sur true à nouveau .
J'espère que cela pourra aider.
MISE À JOUR / NOTES (avril 2015) : Avant de commencer à copier et coller sur ce code, notez que j'ai trouvé quelques exemples où il peut ne pas être fiable à 100% et doit être combiné avec d'autres méthodes pour obtenir les meilleurs résultats. Il existe notamment deux cas connus où le onTrimMemory
rappel n'est pas garanti d'être exécuté:
Si votre téléphone verrouille l'écran pendant que votre application est visible (par exemple, votre appareil se verrouille après nn minutes), ce rappel n'est pas appelé (ou pas toujours) parce que l'écran de verrouillage est juste au-dessus, mais votre application est toujours en cours d'exécution, bien que couverte.
Si votre appareil est relativement faible en mémoire (et soumis à un stress mémoire), le système d'exploitation semble ignorer cet appel et passer directement à des niveaux plus critiques.
Maintenant, selon l'importance pour vous de savoir quand votre application est passée en arrière-plan, vous devrez peut-être étendre cette solution avec le suivi du cycle de vie de l'activité et ainsi de suite.
Gardez simplement à l'esprit ce qui précède et ayez une bonne équipe d'AQ;)
FIN DE MISE À JOUR
Il peut être tard, mais il existe une méthode fiable dans Ice Cream Sandwich (API 14) et au-dessus .
Il s'avère que lorsque votre 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 deux). Cette fonction de rappel n'est disponible qu'en API niveau 14 (Ice Cream Sandwich) et au-dessus.
Vous obtenez essentiellement un appel à la méthode:
public abstract void onTrimMemory (int level)
Le niveau est de 20 ou plus spécifiquement
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 souhaitiez peut-être libérer certaines ressources car votre application n'est plus visible.
Pour citer les documents officiels:
Niveau pour onTrimMemory (int): le processus montrait une interface utilisateur et ne le fait plus. De grandes allocations avec l'interface utilisateur doivent être libérées à ce stade pour permettre une meilleure gestion de la mémoire.
Bien sûr, vous devez l'implémenter pour faire ce qu'il dit (purger la mémoire qui n'a pas été utilisée depuis un certain temps, effacer certaines collections qui étaient inutilisées, etc. Les possibilités sont infinies (voir les documents officiels pour d'autres plus possibles). niveaux critiques ).
Mais, ce qui est intéressant, c'est que le système d'exploitation vous dit: HEY, votre application est passée en arrière-plan!
C'est exactement ce que vous vouliez savoir en premier lieu.
Comment déterminez-vous votre retour?
Eh bien c'est facile, je suis sûr que vous avez une "BaseActivity" afin que vous puissiez utiliser votre onResume () pour signaler le fait que vous êtes de retour. Parce que la seule fois où vous direz que vous n'êtes pas de retour, c'est lorsque vous recevez réellement un appel à la onTrimMemory
méthode ci-dessus .
Ça marche. Vous n'obtenez pas de faux positifs. Si une activité reprend, vous êtes de retour, 100% du temps. Si l'utilisateur retourne à l'arrière, vous recevez un autre onTrimMemory()
appel.
Vous devez vous inscrire à vos activités (ou mieux encore, un cours personnalisé).
Le moyen le plus simple de garantir que vous recevez toujours ceci est de créer une classe simple comme celle-ci:
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, DROIT? ), 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
à cela if
et implémenter ComponentCallbacks
(sans le 2) utilisé dans quoi que ce soit en dessous de l'API 14. Ce rappel n'a que la onLowMemory()
méthode et n'est pas appelé lorsque vous passez en arrière-plan , mais vous devez l'utiliser pour réduire la mémoire .
Maintenant, lancez votre application et appuyez sur home. Votre onTrimMemory(final int level)
méthode doit être appelée (indice: ajouter la journalisation).
La dernière étape consiste à se désinscrire du rappel. Le meilleur endroit est probablement la onTerminate()
méthode de votre application, mais cette méthode n'est pas appelée sur un appareil 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é, car 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 fournissez, par exemple, un mécanisme d'arrêt pour que votre application se nettoie et meure), vous pouvez faire:
unregisterComponentCallbacks(mMemoryBoss);
Et c'est tout.
level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
ce qui évite le problème dans votre mise à jour, point 2. En ce qui concerne le point 1, ce n'est pas un problème pour moi, car l'application n'est pas vraiment passée en arrière-plan, c'est donc la façon dont elle est censée fonctionner.
Voici comment j'ai réussi à résoudre ce problème. Il part du principe que l'utilisation d'une référence temporelle entre les transitions d'activité fournira très probablement des preuves suffisantes qu'une application a été "mise en arrière-plan" ou non.
Tout d'abord, j'ai utilisé une instance android.app.Application (appelons-la MyApplication) qui a un Timer, une TimerTask, une constante pour représenter le nombre maximal 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 l'application était "en arrière-plan" ou non:
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 propose également deux méthodes pour démarrer et arrêter le minuteur / la 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 dont 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();
}
Ainsi, dans le cas où l'utilisateur navigue simplement entre les activités de votre application, la onPause () de l'activité en cours démarre le chronomètre, mais presque immédiatement, la nouvelle activité entrée annule le chronomètre avant qu'il n'atteigne le temps de transition maximum. Et donc, InBackground serait faux .
D'un autre côté, lorsqu'une activité arrive au premier plan à partir du lanceur, le réveil de l'appareil, la fin d'un appel téléphonique, etc., plus que probablement la tâche du minuteur exécutée avant cet événement, et donc InBackground a été défini sur true .
Edit: les nouveaux composants de l'architecture ont apporté quelque chose de prometteur: ProcessLifecycleOwner , voir la réponse de @ 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
}
}
}
Oui. Je sais qu'il est difficile de croire que cette solution simple fonctionne, car nous avons tant de solutions étranges ici.
Mais il y a de l'espoir.
ProcessLifecycleOwner
semble également être une solution prometteuse.
ProcessLifecycleOwner dépêchera
ON_START
,ON_RESUME
événements, un premier se déplace d'activité par ces événements.ON_PAUSE
,ON_STOP
, Les événements seront livrés avec un retard après une dernière activité passée à travers eux. Ce délai est suffisamment long pour garantir queProcessLifecycleOwner
qu'aucun événement ne sera envoyé si les activités sont détruites et recréées en raison d'un changement de configuration.
Une implémentation peut être aussi simple que
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())
Selon le code source, la valeur actuelle du retard est 700ms
.
L'utilisation de cette fonctionnalité nécessite également dependencies
:
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"
implementation "android.arch.lifecycle:extensions:1.0.0"
et annotationProcessor "android.arch.lifecycle:compiler:1.0.0"
du référentiel de Google (c'est-à-dire google()
)
Sur la base de la réponse de Martín Marconcinis (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 Application
public class MyApp extends android.app.Application {
@Override
public void onCreate() {
super.onCreate();
ApplicationLifeCycleHandler handler = new ApplicationLifeCycleHandler();
registerActivityLifecycleCallbacks(handler);
registerComponentCallbacks(handler);
}
}
Nous utilisons cette méthode. Cela semble trop simple pour fonctionner, mais il a été bien testé dans notre application et fonctionne en fait étonnamment bien dans tous les cas, y compris pour accéder à l'écran d'accueil par le bouton "Accueil", par le bouton "Retour" ou après le verrouillage de l'écran. Essaie.
L'idée est que, 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 fonctionne. BTW, Flurry semble utiliser la même logique (juste une supposition, je n'ai pas vérifié cela, mais il accroche aux 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 sommes également passés à onStart () dans les versions ultérieures du code. En outre, j'ajoute des super appels, qui manquaient dans mon message initial, car il s'agissait plus d'un concept que d'un code de travail.
onStop is called when the activity is no longer visible to the user
.
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 qu'au démarrage d'une nouvelle activité, les activités en cours seront interrompues avant la création de la nouvelle. Il en va de même lorsque vous terminez (à l'aide du bouton "retour") une activité.
J'ai trouvé deux méthodes qui semblent fonctionner comme souhaité.
La première nécessite l'autorisation GET_TASKS et consiste en une méthode simple qui vérifie si l'activité en cours d'exécution sur le périphérique appartient à l'application, en comparant les noms de packages:
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 framework Droid-Fu (maintenant appelé Ignition).
La deuxième méthode que j'ai implémentée moi-même ne nécessite pas l'autorisation GET_TASKS, ce qui est bien. 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 activité, vous augmentez la variable et dans onPause () vous la diminuez.
Lorsque le nombre d'activités en cours d'exécution atteint 0, l'application est mise en arrière-plan SI les conditions suivantes sont remplies:
Lorsque vous pouvez détecter que l'application a démissionné en arrière-plan, il est également facile de détecter lorsqu'elle est ramenée au premier plan.
Créez une classe qui s'étend Application
. Ensuite, nous pouvons utiliser sa méthode de remplacement,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
}
}
FragmentActivity
vous pourriez aussi vouloir ajouter level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE
aussi.
Pensez à utiliser onUserLeaveHint. Cela ne sera appelé que lorsque votre application sera en arrière-plan. onPause aura des cas d'angle à 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 bogues lorsque vous pourrez simplement utiliser le rappel onUserLeaveHint qui fait ce que vous demandez.
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. En effet, onResume sera également appelé sur votre activité principale si l'utilisateur n'était que dans votre menu de paramètres et n'a jamais quitté l'application.
N'oubliez pas que si l'utilisateur clique sur le bouton d'accueil dans votre écran de paramètres, onUserLeaveHint sera appelé dans votre activité de paramètres et lorsqu'il reviendra, Resume sera appelé dans votre activité de paramètres. Si vous n'avez que ce code de détection dans votre activité principale, vous raterez 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 prolonger 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 {
...
}
ActivityLifecycleCallbacks peut être intéressant, mais il n'est pas bien documenté.
Cependant, si vous appelez registerActivityLifecycleCallbacks (), vous devriez pouvoir obtenir des rappels lorsque des activités sont créées, détruites, etc. Vous pouvez appeler getComponentName () pour l'activité.
Le package android.arch.lifecycle fournit des classes et des interfaces qui vous permettent de créer des composants adaptés au cycle de vie
Votre application doit implémenter l'interface 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");
}
}
Pour ce faire, vous devez ajouter cette dépendance à votre fichier build.gradle:
dependencies {
implementation "android.arch.lifecycle:extensions:1.1.1"
}
Comme recommandé par Google, vous devez minimiser le code exécuté dans les méthodes d'activités du cycle de vie:
Un modèle courant consiste à implémenter les actions des composants dépendants dans les méthodes de cycle de vie des activités et des fragments. Cependant, ce modèle conduit à une mauvaise organisation du code et à la prolifération des erreurs. En utilisant des composants compatibles avec le cycle de vie, vous pouvez déplacer le code des composants dépendants hors des méthodes de cycle de vie et dans les composants eux-mêmes.
Vous pouvez en savoir plus ici: https://developer.android.com/topic/libraries/architecture/lifecycle
Dans votre application, ajoutez le rappel et vérifiez l'activité root de la manière suivante:
@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();
}
}
});
}
J'ai créé un projet sur Github app-foreground-background-listen
Créez une activité de base pour toutes les activités dans 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
}
}
Utilisez maintenant cette BaseActivity comme une super classe de toutes vos activités comme MainActivity étend BaseActivity et onAppStart sera appelé lorsque vous démarrez votre application et onAppPause () sera appelé lorsque l'application passera en arrière-plan à partir de n'importe quel écran.
C'est assez facile avec ProcessLifecycleOwner
Ajoutez ces dépendances
implementation "android.arch.lifecycle:extensions:$project.archLifecycleVersion"
kapt "android.arch.lifecycle:compiler:$project.archLifecycleVersion"
À 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
Vous pouvez utiliser ProcessLifecycleOwner en y attachant un observateur de cycle de vie.
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");
}
}
puis, dans la onCreate()
classe Application, vous appelez ceci:
ProcessLifecycleOwner.get().getLifecycle().addObserver(new ForegroundLifecycleObserver());
avec cela, vous pourrez capturer les événements ON_PAUSE
et ON_STOP
de votre application qui se produisent quand il passe en arrière-plan.
Il n'y a pas de méthodes de cycle de vie simples pour vous dire quand toute l'application passe en arrière-plan / au premier plan.
Je l'ai fait de manière simple. Suivez les instructions ci-dessous pour détecter la phase d'arrière-plan / de premier plan de l'application.
Avec une petite solution de contournement, c'est possible. Ici, ActivityLifecycleCallbacks vient à la rescousse. Permettez-moi de vous guider pas à pas.
Tout d'abord, créez une classe qui étend android.app.Application et implémente l' interface ActivityLifecycleCallbacks . Dans Application.onCreate (), enregistrez le rappel.
public class App extends Application implements
Application.ActivityLifecycleCallbacks {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
}
Enregistrez la classe «App» dans le manifeste comme ci-dessous <application android:name=".App"
.
Il y aura au moins une activité à l'état démarré lorsque l'application est au premier plan et il n'y aura pas d'activité à l'état démarré lorsque l'application est en arrière-plan.
Déclarez 2 variables comme ci-dessous dans la classe «App».
private int activityReferences = 0;
private boolean isActivityChangingConfigurations = false;
activityReferences
conservera le nombre d'activités dans l' état démarré . isActivityChangingConfigurations
est un indicateur pour indiquer si l'activité en cours subit un changement de configuration comme un commutateur d'orientation.
En utilisant le code suivant, vous pouvez détecter si l'application passe au premier plan.
@Override
public void onActivityStarted(Activity activity) {
if (++activityReferences == 1 && !isActivityChangingConfigurations) {
// App enters foreground
}
}
Voici comment détecter si l'application passe en arrière-plan.
@Override
public void onActivityStopped(Activity activity) {
isActivityChangingConfigurations = activity.isChangingConfigurations();
if (--activityReferences == 0 && !isActivityChangingConfigurations) {
// App enters background
}
}
Comment ça fonctionne:
C'est un petit truc fait avec la façon dont les méthodes de cycle de vie sont appelées en séquence. Permettez-moi de vous présenter un scénario.
Supposons que l'utilisateur lance l'application et que l'activité de lancement A soit lancée. Les appels du cycle de vie seront,
A.onCreate ()
A.onStart () (++ activityReferences == 1) (l'application entre au premier plan)
A.onResume ()
Maintenant, l'activité A commence l'activité B.
A.onPause ()
B.onCreate ()
B.onStart () (++ activityReferences == 2)
B.onResume ()
A.onStop () (--activityReferences == 1)
Ensuite, l'utilisateur revient de l'activité B,
B.onPause ()
A.onStart () (++ activityReferences == 2)
A.onResume ()
B.onStop () (--activityReferences == 1)
B.onDestroy ()
Ensuite, l'utilisateur appuie sur le bouton Accueil,
A.onPause ()
A.onStop () (--activityReferences == 0) (l'application entre en arrière-plan)
Dans le cas, si l'utilisateur appuie sur le bouton Accueil de l'activité B au lieu du bouton Précédent, ce sera toujours le même et les références d'activité seront 0
. Par conséquent, nous pouvons détecter que l'application entre en arrière-plan.
Alors, quel est le rôle de isActivityChangingConfigurations
? Dans le scénario ci-dessus, supposons que l'activité B modifie l'orientation. La séquence de rappel sera,
B.onPause ()
B.onStop () (--activityReferences == 0) (l'application entre en arrière-plan ??)
B.onDestroy ()
B.onCreate ()
B.onStart () (++ activityReferences == 1) (L'application entre au premier plan ??)
B.onResume ()
C'est pourquoi nous avons une vérification supplémentaire isActivityChangingConfigurations
pour éviter le scénario lorsque l'activité passe par les changements de configuration.
J'ai trouvé une bonne méthode pour détecter l'application, que ce soit en avant-plan ou en arrière-plan. Voici mon code . J'espère que cela vous aidera.
/**
* 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();
}
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 (). De la documentation ressort de que cette API est uniquement destinée au débogage et au développement. Je mettrai à jour cet article 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 rédigé un article de blog et créé un simple référentiel GitHub 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 le pas à une activité définie dans la même application, mais elle a un package Java différent. J'ai trouvé un moyen de le faire qui fonctionnera dans ce cas.
Appelez cela dans onPause (), et il vous dira si votre application va en arrière-plan parce qu'une autre application a démarré ou si 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;
}
Bonne réponse ici
Créez 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);
Terminé! Maintenant, lorsque l'application est en arrière-plan, nous obtenons le journal status : we are out
et lorsque nous allons dans l'application, nous obtenons le journalstatus : we are out
Ma solution a été inspirée par la réponse de @ d60402 et repose également sur une fenêtre de temps, 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ù SingletonApplication
est une extension de Application
classe:
public class SingletonApplication extends Application {
public boolean isInBackground = false;
public long lastForegroundTransition = 0;
}
J'utilisais cela avec Google Analytics EasyTracker, et cela a fonctionné. Il pourrait être étendu pour faire ce que vous cherchez en utilisant un simple entier.
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) {
}
});
}
}
Je sais que c'est un peu tard mais je pense que toutes ces réponses ont des problèmes pendant que je le fais comme ci-dessous et cela fonctionne parfaitement.
créer un rappel de cycle de vie d'activité comme celui-ci:
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());
}
Cela semble être l'une des questions les plus compliquées d'Android car (au moment de la rédaction de ce document), Android n'a pas d'équivalent iOS applicationDidEnterBackground()
ni de applicationWillEnterForeground()
rappel. J'ai utilisé une bibliothèque AppState créée par @jenzz .
[AppState est] une bibliothèque Android simple et réactive basée sur RxJava qui surveille les changements d'état des applications. 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é que c'était 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 le 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 .
Il s'agit de la version modifiée de la réponse de @ d60402: https://stackoverflow.com/a/15573121/4747587
Faites tout ce qui y est mentionné. Mais au lieu d'avoir un Base Activity
et d'en faire un parent pour chaque activité et pour remplacer le onResume()
et onPause
, procédez comme suit:
Dans votre classe d'application, ajoutez la ligne:
registerActivityLifecycleCallbacks (rappel Application.ActivityLifecycleCallbacks);
Cela callback
a toutes les méthodes de cycle de vie d'activité et vous pouvez maintenant remplacer onActivityResumed()
et onActivityPaused()
.
Jetez un œil à ce Gist: https://gist.github.com/thsaravana/1fa576b6af9fc8fff20acfb2ac79fa1b
Vous pouvez y parvenir facilement à l'aide de ActivityLifecycleCallbacks
et ComponentCallbacks2
quelque chose comme ci-dessous.
Créez 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 l' Application
implémentation 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 t'aides.
EDIT Comme alternative, vous pouvez maintenant utiliser le composant d'architecture sensible au cycle de vie.
Comme je n'ai trouvé aucune approche, qui gère également la rotation sans vérifier les horodatages, j'ai pensé partager également comment nous le faisons maintenant dans notre application. Le seul ajout à cette réponse https://stackoverflow.com/a/42679191/5119746 est que nous prenons également en compte l'orientation.
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
Ensuite, pour les rappels, nous avons d'abord le CV:
// ActivityLifecycleCallbacks
override fun onActivityResumed(activity: Activity?) {
mResumed++
if (mAppIsInBackground) {
// !!! App came from background !!! Insert code
mAppIsInBackground = false
}
mOrientationWasChanged = false
}
Et onActivityStopped:
override fun onActivityStopped(activity: Activity?) {
if (mResumed == mPaused && !mOrientationWasChanged) {
// !!! App moved to background !!! Insert code
mAppIsInBackground = true
}
Et puis, voici l'ajout: Vérification des changements d'orientation:
override fun onConfigurationChanged(newConfig: Configuration) {
if (newConfig.orientation != mCurrentOrientation) {
mCurrentOrientation = newConfig.orientation
mOrientationWasChanged = true
}
super.onConfigurationChanged(newConfig)
}
C'est ça. J'espère que cela aide quelqu'un :)
Nous pouvons étendre cette solution en utilisant 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
}
}
Maintenant, nous pouvons nous abonner à ce LiveData et attraper les événements nécessaires. Par exemple:
appForegroundStateLiveData.observeForever { state ->
when(state) {
AppForegroundStateLiveData.State.FOREGROUND -> { /* app move to foreground */ }
AppForegroundStateLiveData.State.BACKGROUND -> { /* app move to background */ }
}
}
Ces réponses ne semblent pas être correctes. Ces méthodes sont également appelées lorsqu'une autre activité commence et se termine. Ce que vous pouvez faire est de garder un indicateur global (oui, les globaux sont mauvais :) et définissez-le sur true chaque fois que vous démarrez une nouvelle activité. Réglez-le sur false dans le onCreate de chaque activité. Ensuite, dans la onPause, vous cochez ce drapeau. Si c'est faux, votre application se met en arrière-plan ou elle se fait tuer.