Vérifier si une application Android est en cours d'exécution en arrière-plan

par contexte, je veux dire qu'aucune des activités de l'application n'est actuellement visible pour l'utilisateur?

267
demandé sur Tshepang 2010-09-08 15:04:47

29 réponses

il y a peu de façons de détecter si votre application tourne en arrière-plan, mais une seule d'entre elles est complètement fiable:

  1. la bonne solution (les crédits vont à Dan , CommonsWare et NeTeInStEiN )

    Visibilité de la piste de votre application par vous-même en utilisant Activity.onPause , Activity.onResume méthode. Magasin de "visibilité" dans la classe. Les bons choix sont votre propre mise en œuvre de la Application ou un Service (Il ya aussi quelques variantes de cette solution si vous souhaitez vérifier la visibilité de l'activité du service).

     

    exemple

    Mettre en œuvre la classe Application personnalisée (noter la isActivityVisible() statique la méthode):

    public class MyApplication extends Application {
    
      public static boolean isActivityVisible() {
        return activityVisible;
      }  
    
      public static void activityResumed() {
        activityVisible = true;
      }
    
      public static void activityPaused() {
        activityVisible = false;
      }
    
      private static boolean activityVisible;
    }
    

    enregistrez votre classe de demande dans AndroidManifest.xml :

    <application
        android:name="your.app.package.MyApplication"
        android:icon="@drawable/icon"
        android:label="@string/app_name" >
    

    ajouter onPause et onResume à chaque Activity dans le projet (vous pouvez créer un ancêtre commun pour vos activités si vous le souhaitez, mais si votre activité est déjà étendue de MapActivity / ListActivity etc. vous avez encore besoin d'écrire ce qui suit à la main):

    @Override
    protected void onResume() {
      super.onResume();
      MyApplication.activityResumed();
    }
    
    @Override
    protected void onPause() {
      super.onPause();
      MyApplication.activityPaused();
    }
    



    Update

    ActivityLifecycleCallbacks ont été ajoutés au niveau API 14 (Android 4.0). Vous pouvez les utiliser pour déterminer si une activité de votre application est actuellement visible à l'utilisateur. Cochez Cornstalks 'answer ci-dessous pour les détails.

  2. Le mauvais

    J'ai utilisé proposer la solution suivante:

    vous pouvez détecter l'application actuelle de premier plan/arrière-plan avec ActivityManager.getRunningAppProcesses() qui retourne une liste de RunningAppProcessInfo enregistrements. Pour déterminer si votre demande est à l'avant-plan, cochez la case RunningAppProcessInfo.importance du champ "pour l'égalité RunningAppProcessInfo.IMPORTANCE_FOREGROUND tandis que RunningAppProcessInfo.processName est égal au nom de votre paquet de demande.

    aussi si vous appelez ActivityManager.getRunningAppProcesses() de votre application UI thread il retournera l'importance IMPORTANCE_FOREGROUND pour votre tâche peu importe si elle est réellement au premier plan ou non. L'appeler dans le thread de fond (par exemple via AsyncTask ) et il retournera les résultats corrects.

    bien que cette solution puisse fonctionner (et qu'elle fonctionne en effet la plupart du temps), je recommande fortement de ne pas l'utiliser. Et voici pourquoi. comme Dianne Hackborn a écrit :

    ces API ne sont pas là pour les applications pour baser leur flux D'UI sur, mais pour faire des choses comme montrer à l'utilisateur les applications en cours d'exécution, ou un gestionnaire de tâches, ou autre.

    Oui il y a une liste en mémoire pour ces choses. Cependant, il est désactivé dans un autre processus, géré par des threads fonctionnant séparément du vôtre, et pas quelque chose sur lequel vous pouvez compter (a) voir à temps pour prendre la bonne décision ou (b) avoir une image cohérente au moment où vous revenez. En Plus de la ce n'est qu'à ce moment précis (où l'état de l'activité est brièvement verrouillé pour effectuer l'interrupteur) que nous sommes sûrs de ce que sera la prochaine activité.

    et la mise en œuvre et le comportement global ici ne sont pas garantis de rester les mêmes à l'avenir.

    j'aurais aimé lire ceci avant de poster une réponse j'espère qu'il n'est pas trop tard pour admettre mon erreur.

  3. une autre mauvaise solution

    Droid-Fu bibliothèque mentionnée dans l'une des réponses utilise ActivityManager.getRunningTasks pour sa méthode isApplicationBroughtToBackground . Voir le commentaire de Dianne ci-dessus et n'utilisez pas cette méthode non plus.

371
répondu Idolon 2017-05-23 12:26:26

N'UTILISEZ PAS CETTE RÉPONSE

user1269737 réponse est la bonne (Google/Android approuvé) façon de le faire . Allez lire leur réponse et donnez-leur un +1.

je laisse ma réponse originale ici pour la postérité. C'était le meilleur disponible en 2012, mais maintenant Android a le soutien approprié pour cela.

réponse originale

la clé est en utilisant ActivityLifecycleCallbacks (notez que cela nécessite une API Android niveau 14 (Android 4.0)). Il suffit de vérifier si le nombre d'activités interrompues est égal au nombre d'activités commencées. Si elles sont égales, votre application est en arrière-plan. S'il y a d'autres activités lancées, votre demande est toujours visible. S'il y a plus de reprise que d'activités interrompues, votre demande est non seulement visible, mais elle est aussi au premier plan. Il existe 3 principaux membres de votre activité, alors: visible et au premier plan, visible mais pas au premier plan, et non visible et non pas au premier plan (c'est à dire dans le fond).

ce qui est vraiment bien avec cette méthode, c'est qu'elle n'a pas les problèmes asynchrones getRunningTasks() fait, mais vous n'avez pas non plus à modifier chaque Activity dans votre application pour définir/désactiver quelque chose dans onResumed() / onPaused() . C'est juste quelques lignes de code qui sont autonomes, et cela fonctionne dans toute votre application. Majoré, il n'y a pas funky autorisations requises.

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

MyApplication.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é quelques bonnes questions sur cette méthode que je voudrais répondre à cette réponse pour tout le monde:

onStop() n'est pas appelé en mémoire basse les situations; est-ce un problème ici?

Pas de. Les docs pour onStop() disent:

notez que cette méthode ne peut jamais être appelée, dans les situations de mémoire faible où le système n'a pas assez de mémoire pour garder le processus de votre activité en cours après que sa méthode onPause() est appelée.

La clé ici est de ne conserver que votre activité processus en cours ..."Si ce faible la situation de mémoire est jamais atteinte, votre processus est réellement tué (pas seulement votre activité). Cela signifie que cette méthode de vérification de backgrounded-ness est toujours valide parce que a) vous ne pouvez pas vérifier la backgroundounding de toute façon si votre processus est tué, et b) si votre processus recommence (parce qu'une nouvelle activité est créée), les variables membres (statiques ou non) pour MyLifecycleHandler seront réinitialisées à 0 .

Fait ce travail pour la configuration les changements?

par défaut, no. Vous devez explicitement définir configChanges=orientation|screensize ( | avec tout ce que vous voulez) dans votre fichier de manifestes et gérer les changements de configuration, sinon votre activité sera détruite et recréée. Si vous ne définissez pas cela, 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 voir, 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, ce qui la semi-finition-la méthode de détection de travaux). Pour contourner cela, vous devez mettre configChanges pour que votre activité ne soit pas détruite. Heureusement, j'ai dû mettre configChanges déjà dans tous mes projets parce qu'il n'était pas souhaitable que toute mon activité soit détruite à l'écran tourner/redimensionner, donc je n'ai jamais trouvé cela problématique. (merci à dpimka pour rafraîchir ma mémoire sur ce et me corriger!)

Une note:

quand j'ai dit "background" ici dans cette réponse, j'ai voulu dire "votre application n'est plus visible."Les activités Android peuvent être visibles mais pas au premier plan (par exemple, s'il y a une superposition transparente de notification). C'est pourquoi j'ai mis à jour cette réponse pour refléter cela.

il est important de savoir que Android a un moment limbo étrange lors de la commutation des activités où rien 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 votre Activity 's onPause() méthode après super.onPause() . Souviens-toi de l'état limbo bizarre dont je viens de parler.

vous pouvez vérifier si votre application est visible (i.e. si ce n'est pas en arrière-plan) dans votre Activity 's onStop() méthode après super.onStop() .

252
répondu Cornstalks 2018-09-08 03:22:45

GOOGLE SOLUTION - pas un hack, comme les solutions précédentes. Use ProcessLifecycleOwner

class ArchLifecycleApp : Application(), LifecycleObserver {

    override fun onCreate() {
        super.onCreate()
        ProcessLifecycleOwner.get().lifecycle.addObserver(this)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onAppBackgrounded() {
        //App in background
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onAppForegrounded() {
        // App in foreground
    }

}

dans l'app.Grad

dependencies {
    ...
    implementation "android.arch.lifecycle:extensions:1.1.0"
}

allprojects {
    repositories {
        ...
        google()
        jcenter()
        maven { url 'https://maven.google.com' }
    }
}
24
répondu user1269737 2018-02-13 13:18:58

Idolon la réponse est sujette aux erreurs et beaucoup plus compliqué malgré repeatead ici vérifier l'application android est en premier plan ou pas? et ici détermination de l'application actuelle des connaissances nouvelles à partir d'une tâche ou d'un service

il y a une approche beaucoup plus simple:

sur la base que toutes les activités s'étendent:

protected static boolean isVisible = false;

 @Override
 public void onResume()
 {
     super.onResume();
     setVisible(true);
 }


 @Override
 public void onPause()
 {
     super.onPause();
     setVisible(false);
 }

Chaque fois que vous devez cocher si l'une de vos activités d'application est en premier plan, cochez isVisible() ;

Pour comprendre cette approche vérifier cette réponse de side-by-side de l'activité du cycle de vie: "1519190920 l'Activité" side-by-side de cycle de vie

16
répondu neteinstein 2017-05-23 12:26:26

depuis Android API 16 Il ya un moyen simple de vérifier si l'application est à l'avant-plan. Il peut ne pas être infaillible, mais aucune méthode sur Android sont infaillibles. Cette méthode est assez bonne à utiliser lorsque votre service reçoit la mise à jour du serveur et doit décider si Afficher la notification, ou non (parce que si L'interface utilisateur est au premier plan, l'utilisateur remarquera la mise à jour sans notification).

RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
11
répondu Juozas Kontvainis 2017-04-17 16:19:31

j'ai essayé la solution recommandée qui utilise L'Application .ActivityLifecycleCallbacks et beaucoup d'autres, mais ils n'ont pas fonctionné comme prévu. Grâce à Sarge , j'ai trouvé une solution assez simple et directe que je décris ci-dessous.

ils clé de la solution est le fait de comprendre que si nous avons ActivityA et ActivityB, et nous appelons ActivityB D'ActivityA (et non appeler ActivityA.finish ), puis ActivityB onStart() sera appelé avant ActivityA onStop() .

c'est aussi la principale différence entre onStop() et onPause() que personne n'a mentionnée dans les articles que j'ai lus.

donc basé sur le comportement du cycle de vie de cette activité, vous pouvez simplement compter combien de fois onStart() et onPause() ont été appelés dans votre programme. Notez que pour chaque Activity de votre programme, vous devez outrepasser onStart() et onStop() , afin d'incrémenter/décrémenter la variable statique utilisée pour compter. Voici le code qui implémente cette logique. Notez que j'utilise une classe qui s'étend Application , alors n'oubliez pas de déclarer sur Manifest.xml étiquette D'Application intérieure: android:name=".Utilities" , bien qu'il puisse être mis en œuvre en utilisant une classe personnalisée simple aussi.

public class Utilities extends Application
{
    private static int stateCounter;

    public void onCreate()
    {
        super.onCreate();
        stateCounter = 0;
    }

    /**
     * @return true if application is on background
     * */
    public static boolean isApplicationOnBackground()
    {
        return stateCounter == 0;
    }

    //to be called on each Activity onStart()
    public static void activityStarted()
    {
        stateCounter++;
    }

    //to be called on each Activity onStop()
    public static void activityStopped()
    {
        stateCounter--;
    }
}

maintenant sur chaque activité de notre programme, nous devrions remplacer onStart() et onStop() et incrément / décrément comme indiqué ci-dessous:

@Override
public void onStart()
{
    super.onStart();
    Utilities.activityStarted();
}

@Override
public void onStop()
{
    Utilities.activityStopped();
    if(Utilities.isApplicationOnBackground())
    {
        //you should want to check here if your application is on background
    }
    super.onStop();
}

avec cette logique, il y a 2 cas possibles:

  1. stateCounter = 0 : le nombre d'arrêts est égal au nombre d'activités commencées, ce qui signifie que l'application tourne sur le fond.
  2. stateCounter > 0 : le nombre de démarrés est plus grand que le nombre de l'arrêté, ce qui signifie que l'application est en cours d'exécution sur le premier plan.

avis: stateCounter < 0 signifierait qu'il y a plus d'activités interrompues que de démarrées, ce qui est impossible. Si vous rencontrez ce cas, cela signifie que vous n'êtes pas augmenter/de diminuer le compteur que vous devriez.

vous êtes prêt à partir. Vous devriez vérifier si votre demande est en arrière-plan dans onStop() .

10
répondu Menelaos Kotsollaris 2017-05-23 12:34:37

il n'y a aucun moyen, à moins que vous le suiviez vous-même, de déterminer si l'une de vos activités est visible ou non. Peut-être devriez-vous envisager de poser une nouvelle question sur StackOverflow, en expliquant ce que vous essayez de réaliser à partir d'une expérience utilisateur, afin que nous puissions peut-être vous donner des idées alternatives de mise en œuvre.

7
répondu CommonsWare 2010-09-08 11:35:36

vous pouvez utiliser ComponentCallbacks2 pour détecter si l'application est en arrière-plan. BTW ce rappel est seulement disponible dans le niveau API 14 (Sandwich à la crème glacée) et au-dessus.

vous recevrez un appel à la méthode:

public abstract void onTrimMemory (int level)

si le niveau est ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN alors que l'application est en arrière-plan.

vous pouvez implémenter cette interface à un activity , service , etc.

public class MainActivity extends AppCompatActivity 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) {
        // app is in background
     }
   }
}
5
répondu Rohit Arya 2016-03-30 21:09:34

en S'appuyant sur @Cornstalks réponse à inclure un couple de fonctionnalités utiles.

Caractéristiques supplémentaires:

  • modèle introduit singleton donc vous pouvez le faire n'importe où dans l'application: AppLifecycleHandler.isApplicationVisible () et AppLifecycleHandler.isapplicationinforground ()
  • ajout du traitement des événements en double (voir les commentaires / / prendre des mesures pour changer la visibilité et / / prendre des mesures pour changer la visibilité) premier plan)

App.java

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        registerActivityLifecycleCallbacks(AppLifecycleHandler.getInstance());
    }
}

AppLifecycleHandler.java

public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
    private int resumed;
    private int started;

    private final String DebugName = "AppLifecycleHandler";

    private boolean isVisible = false;
    private boolean isInForeground = false;

    private static AppLifecycleHandler instance;

    public static AppLifecycleHandler getInstance() {
        if (instance == null) {
            instance = new AppLifecycleHandler();
        }

        return instance;
    }

    private AppLifecycleHandler() {
    }

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

    @Override
    public void onActivityDestroyed(Activity activity) {
    }

    @Override
    public void onActivityResumed(Activity activity) {
        ++resumed;
        android.util.Log.w(DebugName, "onActivityResumed -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
        setForeground((resumed > 0));
    }

    @Override
    public void onActivityPaused(Activity activity) {
        --resumed;
        android.util.Log.w(DebugName, "onActivityPaused -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
        setForeground((resumed > 0));
    }

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

    @Override
    public void onActivityStarted(Activity activity) {
        ++started;
        android.util.Log.w(DebugName, "onActivityStarted -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
        setVisible((started > 0));
    }

    @Override
    public void onActivityStopped(Activity activity) {
        --started;
        android.util.Log.w(DebugName, "onActivityStopped -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
        setVisible((started > 0));
    }

    private void setVisible(boolean visible) {
        if (isVisible == visible) {
            // no change
            return;
        }

        // visibility changed
        isVisible = visible;
        android.util.Log.w(DebugName, "App Visiblility Changed -> application is visible: " + isVisible);

        // take some action on change of visibility
    }

    private void setForeground(boolean inForeground) {
        if (isInForeground == inForeground) {
            // no change
            return;
        }

        // in foreground changed
        isInForeground = inForeground;
        android.util.Log.w(DebugName, "App In Foreground Changed -> application is in foreground: " + isInForeground);

        // take some action on change of in foreground

    }

    public static boolean isApplicationVisible() {
        return AppLifecycleHandler.getInstance().started > 0;
    }

    public static boolean isApplicationInForeground() {
        return AppLifecycleHandler.getInstance().resumed > 0;
    }
}
4
répondu seb 2016-11-23 16:13:18

la meilleure solution que j'ai trouvé utilise des minuteries.

vous avez démarrer une minuterie dans onPause() et annuler la même minuterie dans onResume(), il y a 1 instance de la minuterie (habituellement définie dans la classe Application). La minuterie elle-même est réglée pour exécuter une exécutable après 2 secondes (ou n'importe quel intervalle que vous jugez approprié), lorsque la minuterie démarre vous mettez un drapeau marquant l'application comme étant en arrière-plan.

dans la méthode onResume() avant d'annuler la minuterie, vous pouvez interroger le drapeau d'arrière-plan pour effectuer toutes les opérations de démarrage (par exemple démarrer les téléchargements ou activer les services de localisation).

cette solution vous permet d'avoir plusieurs activités sur la pile arrière, et ne nécessite pas d'autorisations pour l'implémentation.

cette solution fonctionne bien si vous utilisez un bus d'événements aussi, car votre minuterie peut simplement lancer un événement et diverses parties de votre application peuvent répondre en conséquence.

3
répondu Andrew Kelly 2014-02-13 03:16:00

si vous activez les paramètres du développeur" ne gardez pas d'activités " - vérifiez que seul le nombre d'activités créées n'est pas suffisant. Vous devez également vérifier isSaveInstanceState . Ma méthode personnalisée isApplicationRunning() vérifier est l'application android est en cours d'exécution:

Voici mon code de travail:

public class AppLifecycleService implements Application.ActivityLifecycleCallbacks {
    private int created;
    private boolean isSaveInstanceState;
    private static AppLifecycleService instance;

    private final static String TAG = AppLifecycleService.class.getName();

    public static AppLifecycleService getInstance() {
        if (instance == null) {
            instance = new AppLifecycleService();
        }
        return instance;
    }

    public static boolean isApplicationRunning() {
        boolean isApplicationRunning = true;
        if (getCountCreatedActvities() == 0 && !isSaveInstanceState()) {
            isApplicationRunning = false;
        }
        return isApplicationRunning;
    }

    public static boolean isSaveInstanceState() {
        return AppLifecycleService.getInstance().isSaveInstanceState;
    }

    public static int getCountCreatedActvities() {
        return AppLifecycleService.getInstance().created;
    }

    private AppLifecycleService() {
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        this.isSaveInstanceState = true;
    }

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        ++created;
    }

    @Override
    public void onActivityDestroyed(Activity activity) {
        --created;
    }

    @Override
    public void onActivityResumed(Activity activity) {   }

    @Override
    public void onActivityPaused(Activity activity) { }


    @Override
    public void onActivityStarted(Activity activity) { }

    @Override
    public void onActivityStopped(Activity activity) { }        

}
3
répondu Alexei 2017-01-29 16:57:44

pour piggyback sur ce que CommonsWare et Key ont dit, vous pourriez peut-être étendre la classe D'Application et avoir toutes vos activités font appel à leurs méthodes onPause/onResume. Cela vous permettra de savoir quelle Activité(s) sont visibles, mais cela pourrait être mieux gérés.

pouvez-vous préciser ce que vous avez exactement en tête? Quand vous dites courir en arrière - plan vous voulez dire simplement avoir votre application encore dans la mémoire, même si elle n'est pas actuellement à l'écran? Avez-vous envisagé l'utilisation des Services comme un moyen plus persistant de gérer votre application alors qu'elle n'est pas au point?

2
répondu Dan 2010-09-08 12:38:24

j'ai fait ma propre implémentation de ActivityLifecycleCallbacks. J'utilise L'activité Sherlock, mais pour une activité normale, le cours pourrait marcher.

tout d'abord, je crée une interface qui a toutes les méthodes pour suivre le cycle de vie des activités:

public interface ActivityLifecycleCallbacks{
    public void onActivityStopped(Activity activity);
    public void onActivityStarted(Activity activity);
    public void onActivitySaveInstanceState(Activity activity, Bundle outState);
    public void onActivityResumed(Activity activity);
    public void onActivityPaused(Activity activity);
    public void onActivityDestroyed(Activity activity);
    public void onActivityCreated(Activity activity, Bundle savedInstanceState);
}

Deuxièmement, j'ai implémenté cette interface dans la classe de mon Application:

public class MyApplication extends Application implements my.package.ActivityLifecycleCallbacks{

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

    @Override
    public void onActivityStopped(Activity activity) {
        Log.i("Tracking Activity Stopped", activity.getLocalClassName());

    }

    @Override
    public void onActivityStarted(Activity activity) {
        Log.i("Tracking Activity Started", activity.getLocalClassName());

    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
    }

    @Override
    public void onActivityResumed(Activity activity) {
        Log.i("Tracking Activity Resumed", activity.getLocalClassName());
    }

    @Override
    public void onActivityPaused(Activity activity) {
        Log.i("Tracking Activity Paused", activity.getLocalClassName());
    }

    @Override
    public void onActivityDestroyed(Activity activity) {
        Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
    }

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        Log.i("Tracking Activity Created", activity.getLocalClassName());
    }
}

Troisièmement, je crée une classe qui s'étend de L'activité Sherlock:

public class MySherlockActivity extends SherlockActivity {

    protected MyApplication nMyApplication;

    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        nMyApplication = (MyApplication) getApplication();
        nMyApplication.onActivityCreated(this, savedInstanceState);
    }

    protected void onResume() {
        // TODO Auto-generated method stub
        nMyApplication.onActivityResumed(this);
        super.onResume();

    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        nMyApplication.onActivityPaused(this);
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        nMyApplication.onActivityDestroyed(this);
        super.onDestroy();
    }

    @Override
    protected void onStart() {
        nMyApplication.onActivityStarted(this);
        super.onStart();
    }

    @Override
    protected void onStop() {
        nMyApplication.onActivityStopped(this);
        super.onStop();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        nMyApplication.onActivitySaveInstanceState(this, outState);
        super.onSaveInstanceState(outState);
    }   
}

Quatrièmement, toute classe qui s'étend de SherlockActivity, j'ai remplacé pour MySherlockActivity:

public class MainActivity extends MySherlockActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

}

maintenant, dans le logcat vous verrez les journaux programmés dans l'implémentation de L'Interface faite dans MyApplication.

2
répondu ClarkXP 2013-01-23 00:14:20
L'activité

est en pause quand un dialogue vient au-dessus de lui de sorte que toutes les solutions recommandées sont des demi-solutions. Vous devez créer crochets pour les dialogues.

1
répondu konmik 2015-10-03 09:39:38

Puisqu'il n'est pas déjà mentionné, je vais suggérer aux lecteurs d'explorer ProcessLifecycleOwner disponible par composants D'Architecture Android

1
répondu Rachit Mishra 2018-01-29 11:46:20

documents officiels:

le système distingue entre les applications de premier plan et de fond. (La définition de background for purposes of service limitations est distincte de celle utilisée par memory management; une application peut être à l'arrière-plan en ce qui concerne memory management , mais à l'avant-plan en ce qui concerne sa capacité à lancer des services.) Une application est considérée comme faisant partie du premier plan si l'une des conditions suivantes est vraie:

  1. il s'agit d'une activité visible, qu'elle soit commencée ou interrompue.
  2. il a un service de premier plan.
  3. une autre application de premier plan est liée à l'application, soit en liant l'application à l'un de ses services, soit en utilisant l'un de ses fournisseurs de contenu. Par exemple, l'application est au premier plan si une autre application se lie à son:
    • IME
    • service de papier peint
    • Notification listener
    • la Voix ou le texte de service

Si aucune de ces deux conditions est vraie, l'application est en arrière-plan.

1
répondu Uddhav Gautam 2018-02-01 00:52:16

une autre solution pour ce vieux poteau (pour ceux qu'il pourrait aider):


<application android:name=".BaseApplication" ... >

public class BaseApplication extends Application {

    private class Status {
        public boolean isVisible = true;
        public boolean isFocused = true;
    }

    private Map<Activity, Status> activities;

    @Override
    public void onCreate() {
        activities = new HashMap<Activity, Status>();
        super.onCreate();
    }

    private boolean hasVisibleActivity() {
        for (Status status : activities.values())
            if (status.isVisible)
                return true;
        return false;
    }

    private boolean hasFocusedActivity() {
        for (Status status : activities.values())
            if (status.isFocused)
                return true;
        return false;
    }

    public void onActivityCreate(Activity activity, boolean isStarting) {
        if (isStarting && activities.isEmpty())
            onApplicationStart();
        activities.put(activity, new Status());
    }

    public void onActivityStart(Activity activity) {
        if (!hasVisibleActivity() && !hasFocusedActivity())
            onApplicationForeground();
        activities.get(activity).isVisible = true;
    }

    public void onActivityWindowFocusChanged(Activity activity, boolean hasFocus) {
        activities.get(activity).isFocused = hasFocus;
    }

    public void onActivityStop(Activity activity, boolean isFinishing) {
        activities.get(activity).isVisible = false;
        if (!isFinishing && !hasVisibleActivity() && !hasFocusedActivity())
            onApplicationBackground();
    }

    public void onActivityDestroy(Activity activity, boolean isFinishing) {
        activities.remove(activity);
        if(isFinishing && activities.isEmpty())
            onApplicationStop();
    }

    private void onApplicationStart() {Log.i(null, "Start");}
    private void onApplicationBackground() {Log.i(null, "Background");}
    private void onApplicationForeground() {Log.i(null, "Foreground");}
    private void onApplicationStop() {Log.i(null, "Stop");}

}

public class MyActivity extends BaseActivity {...}

public class BaseActivity extends Activity {

    private BaseApplication application;

    @Override
    protected void onCreate(Bundle state) {
        application = (BaseApplication) getApplication();
        application.onActivityCreate(this, state == null);
        super.onCreate(state);
    }

    @Override
    protected void onStart() {
        application.onActivityStart(this);
        super.onStart();
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        application.onActivityWindowFocusChanged(this, hasFocus);
        super.onWindowFocusChanged(hasFocus);
    }

    @Override
    protected void onStop() {
        application.onActivityStop(this, isFinishing());
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        application.onActivityDestroy(this, isFinishing());
        super.onDestroy();
    }

}
0
répondu alex 2014-03-03 11:04:38

voir le commentaire dans la fonction onActivityDestroyed.

fonctionne avec la version cible SDK 14>:

import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;

public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {

    public static int active = 0;

    @Override
    public void onActivityStopped(Activity activity) {
        Log.i("Tracking Activity Stopped", activity.getLocalClassName());
        active--;
    }

    @Override
    public void onActivityStarted(Activity activity) {
        Log.i("Tracking Activity Started", activity.getLocalClassName());
        active++;
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
    }

    @Override
    public void onActivityResumed(Activity activity) {
        Log.i("Tracking Activity Resumed", activity.getLocalClassName());
        active++;
    }

    @Override
    public void onActivityPaused(Activity activity) {
        Log.i("Tracking Activity Paused", activity.getLocalClassName());
        active--;
    }

    @Override
    public void onActivityDestroyed(Activity activity) {
        Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
        active--;

        // if active var here ever becomes zero, the app is closed or in background
        if(active == 0){
            ...
        }

    }

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        Log.i("Tracking Activity Created", activity.getLocalClassName());
        active++;
    }
}
0
répondu ramden 2014-12-08 13:05:34

vous devez utiliser une préférence partagée pour stocker la propriété et d'agir sur elle en utilisant service binding de vos activités. Si vous utilisez binding seulement, (ce qui n'est jamais utiliser startService), alors votre service ne s'exécute que lorsque vous vous liez à lui, (bind onResume et unbind onPause) qui le ferait fonctionner sur le premier plan seulement, et si vous voulez travailler sur le fond, vous pouvez utiliser le service régulier start stop.

0
répondu Ofek Ron 2014-12-18 12:24:36

je pense que cette question devrait être plus claire. Quand? Où? Quelle est votre situation spécifique vous voulez konw si votre application est en arrière-plan?

je présente juste ma solution à ma façon.

J'obtiens ceci en utilisant le champ "importance" de RunningAppProcessInfo classe dans chaque activité onStop méthode dans mon application, qui peut être simplement atteint en fournissant un BaseActivity pour d'autres activités d'étendre qui met en œuvre la méthode onStop pour vérifier la valeur de "l'importance". Voici le code:

public static boolean isAppRunning(Context context) {
    ActivityManager activityManager = (ActivityManager) context
        .getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningAppProcessInfo> appProcesses = activityManager
        .getRunningAppProcesses();
    for (RunningAppProcessInfo appProcess : appProcesses) {
        if (appProcess.processName.equals(context.getPackageName())) {
            if (appProcess.importance != RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE) {
                return true;
            } 
        }
    }
    return false;
}
0
répondu wxf04125 2015-03-20 04:26:09

je vous recommande de lire à travers cette page: http://developer.android.com/reference/android/app/Activity.html

En bref, votre activité n'est plus visible après onStop() a été appelé.

0
répondu Key 2015-12-10 13:32:04

Qu'en est-il de l'utilisation de getApplicationState().isInForeground ()?

0
répondu jonney 2016-02-15 14:30:22

à mon avis, beaucoup de réponses introduisent une lourde charge de code et apportent beaucoup de complexité et de non-lisibilité.

quand les gens demandent ainsi comment communiquer entre un Service et un Activity , je conseille habituellement d'utiliser le "151961092020" gestionnaire local .


pourquoi?

bien, en citant les docs:

  • vous savez que les données que vous diffusez ne quitteront pas votre application, ne vous inquiétez donc pas de la fuite de données privées.

  • il n'est pas possible pour d'autres applications d'envoyer ces émissions à votre application, donc vous n'avez pas à vous soucier d'avoir des trous de sécurité qu'ils peuvent exploiter.

  • Il est plus efficace que l'envoi d'une diffusion mondiale, par le biais de la système.

Pas les docs:

  • Il ne nécessite pas de bibliothèques externes
  • le code est minimal
  • C'est rapide à mettre en œuvre et à comprendre
  • Non personnalisé de l'auto-mise en œuvre des rappels / ultra-singleton / intra-processus motif que ce soit...
  • Pas de solides références sur Activity , Application , ...

Description

Alors, vous voulez vérifier si l'un des Activity est actuellement au premier plan. Vous le faites habituellement dans une classe Service , ou dans votre classe Application .

cela signifie que vos objets Activity deviennent l'expéditeur d'un signal (je suis on / je suis off). Votre Service , d'autre part, devient le Receiver .

Il y a deux des moments où votre Activity vous indique si il va au premier plan ou en arrière-plan (oui seulement deux... pas 6).

lorsque le Activity apparaît au premier plan, la méthode onResume() est déclenchée (également appelée après onCreate() ).

Quand le Activity va dans le dos, onPause() est appelé.

ce sont les moments dans lesquels votre Activity devrait envoyer le signal à votre Service pour décrire son état.

en cas de multiple Activity 's, se souvenir de l'an Activity va dans l'arrière-plan d'abord, puis un autre vient à l'avant-plan.

Donc, la situation serait la suivante:*

Activity1 -- send --> Signal:OFF
Activity2 -- send --> Signal:ON

le Service / Application continuera simplement d'écouter ces signaux et d'agir en conséquence.


Code (TLDR)

votre Service doit implémenter un BroadcastReceiver afin d'écouter les signaux.

this.localBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // received data if Activity is on / off
    }
}

public static final IntentFilter SIGNAL_FILTER = new IntentFilter("com.you.yourapp.MY_SIGNAL") 

Enregistrer le Receiver dans Service::onCreate()

@Override
protected void onCreate() {
    LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}

de l'Onu-l'enregistrer dans Service::onDestroy()

@Override
protected void onDestroy() {
    // I'm dead, no need to listen to anything anymore.
    LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}

maintenant votre Activity doit communiquer leur état.

In Activity::onResume()

Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent    
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);

Dans Activity::onPause()

Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put OFF boolean in intent    
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);

une situation très, très courante

Developer: je veux envoyer des données de mon Service et mettre à jour le Activity . Comment puis-je vérifier si le Activity est au premier plan?

il n'est généralement pas nécessaire de vérifier si le Activity est au premier plan ou non. Il suffit d'envoyer les données via LocalBroadcastManager à partir de votre Service . Si le Activity est activé, il réagira et agira.

pour cette situation très courante, le Service devient l'expéditeur, et le Activity implémente le BroadcastReceiver .

ainsi, créer un Receiver dans votre Activity . Enregistrez-le dans onResume() et annulez-le dans onPause() . Il n'est pas nécessaire d'utiliser les autres méthodes de cycle de vie .

Définir le Receiver comportement onReceive() (mise à jour ListView, fais ceci, fais cela, ...).

de cette façon le Activity écoutera seulement si c'est au premier plan et rien n'arrivera si c'est dans le dos ou est détruit.

en cas de multiple Activity 's, celui qui Activity est sur va répondre (s'ils mettent également en œuvre le Receiver ).

si tout est à l'arrière-plan, personne ne répondra et le signal sera simplement perdu.

envoyer les données du Service via Intent (voir code ci-dessus) en spécifiant le signal ID.


0
répondu Marko Pacak 2018-01-30 14:32:51

la seule solution correcte:

activité principale.java:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        MyApp.mainActivity = this;
        super.onCreate(savedInstanceState);
        ...
    }

MyApp.java:

public class MyApp extends Application implements LifecycleObserver {

    public static MainActivity mainActivity = null;

    @Override
    public void onCreate() {
        super.onCreate();
        ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void onAppBackgrounded() {
        // app in background
        if (mainActivity != null) {
            ...
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    void onAppForegrounded() {
        // app in foreground
        if (mainActivity != null) {
            ...
        }
    }

}
0
répondu Dmitry 2018-09-07 07:40:18

bibliothèque de soutien de démarrage version 26 Vous pouvez utiliser propriétaire de processus , il suffit de l'ajouter à votre dépendance comme décrit ici , par exemple:

dependencies {
    def lifecycle_version = "1.1.1"

    // ViewModel and LiveData
    implementation "android.arch.lifecycle:extensions:$lifecycle_version"
    // alternatively - Lifecycles only (no ViewModel or LiveData).
    //     Support library depends on this lightweight import
    implementation "android.arch.lifecycle:runtime:$lifecycle_version"
    annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" // use kapt for Kotlin
}

et puis juste interroger ProcessLifecycleOwner chaque fois que vous voulez pour l'État app, exemples:

//Check if app is in background
ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED;

//Check if app is in foreground
ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);
0
répondu Keivan Esbati 2018-10-06 10:50:03

dans Mes activités onResume et onPause j'écris un booléen isVisible à des références partagées.

    SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
    Editor editor = sharedPrefs.edit();
    editor.putBoolean("visible", false);
    editor.commit();

et le lire ailleurs si nécessaire via,

    // Show a Toast Notification if App is not visible (ie in background. Not running, etc) 
    SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
    if(!sharedPrefs.getBoolean("visible", true)){...}

peut-être pas Élégant, mais ça marche pour moi...

-1
répondu mtwagner 2012-06-18 14:53:15

il est peut-être trop tard pour répondre mais si quelqu'un vient en visite alors voici la solution que je suggère, La raison(s) une application veut savoir son état d'être en arrière-plan ou de venir à l'avant-plan peut être beaucoup, quelques-uns sont, 1. Pour afficher des toasts et des notifications lorsque l'utilisateur est en BG. 2.Pour effectuer certaines tâches pour la première fois Utilisateur vient de BG, comme un sondage, redessiner etc.

la solution D'Idolon et d'autres s'occupe de la première partie, mais ne s'occupe pas de la seconde. S'il y a plusieurs activités dans votre application, et que l'utilisateur change entre elles, alors au moment où vous êtes dans la deuxième activité, le drapeau visible sera faux. Elle ne peut donc pas être utilisée de manière déterministe.

j'ai fait quelque chose ce qui a été suggéré par CommonsWare, "si le Service détermine qu'il n'y a aucune activité visible, et il reste de cette façon pendant un certain temps , arrêter le transfert de données au prochain point d'arrêt logique."

la ligne en caractères gras est importante et peut être utilisée pour obtenir le deuxième élément. Donc ce que je fais , c'est une fois que j'ai l'onActivityPaused (), ne changez pas le visible en false directement, au lieu d'avoir un timer de 3 secondes (c'est-à-dire le max que la prochaine activité doit être lancée), et s'il n'y a pas d'appel onActivityResumed() dans les 3 secondes suivantes, changez visible en false. De même dans onActivityResumed() s'il y a un timer, Je l'annule. En résumé, le visible devient isAppInBackground.

désolé ne peut pas copier-coller le code...

-1
répondu Sriram 2013-10-03 08:00:34

une autre solution simple et précise. Complète de l'essentiel ici

public class BaseLifeCycleCallbacks implements Application.ActivityLifecycleCallbacks {


HashMap<String, Integer> activities;

BaseLifeCycleCallbacks() {
    activities = new HashMap<String, Integer>();
}

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

@Override
public void onActivityStarted(Activity activity) {
    //map Activity unique class name with 1 on foreground
    activities.put(activity.getLocalClassName(), 1);
    applicationStatus();
}

@Override
public void onActivityResumed(Activity activity) {
}

@Override
public void onActivityPaused(Activity activity) {
}

@Override
public void onActivityStopped(Activity activity) {
    //map Activity unique class name with 0 on foreground
    activities.put(activity.getLocalClassName(), 0);
    applicationStatus();
}

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

}

@Override
public void onActivityDestroyed(Activity activity) {
}

/**
 * Check if any activity is in the foreground
 */
private boolean isBackGround() {
    for (String s : activities.keySet()) {
        if (activities.get(s) == 1) {
            return false;
        }
    }
    return true;
}

/**
 * Log application status.
 */
private void applicationStatus() {
    Log.d("ApplicationStatus", "Is application background" + isBackGround());
    if (isBackGround()) {
        //Do something if the application is in background
    }
}
-1
répondu mipreamble 2015-03-21 20:02:58

je voudrais vous recommander d'utiliser une autre façon de le faire.

je suppose que vous voulez montrer l'écran de démarrage pendant que le programme commence, s'il est déjà en marche arrière, ne pas le montrer.

votre application peut écrire en continu l'heure actuelle à un dossier spécifique. Pendant le démarrage de votre application, vérifiez la dernière estampille de temps, si current_time-last_time>l'intervalle de temps que vous avez spécifié pour écrire la dernière heure, cela signifie que votre application est arrêté, soit tué par le système ou l'utilisateur lui-même.

-3
répondu user2322866 2013-04-26 08:03:47