Comment vérifier si l'activité est au premier plan ou en arrière-plan visible?

j'ai un écran splash sur une minuterie. Mon problème est qu'avant de finish() mon activité je dois vérifier que l'activité suivante a commencé parce qu'une boîte de dialogue Système apparaît et je veux seulement finish() ; une fois que l'Utilisateur a choisi une option de la boîte de dialogue?

je sais qu'il y a beaucoup de questions sur la façon de voir si votre activité est au premier plan, mais je ne sais pas si cela permet des boîtes de dialogue au-dessus de l'activité aussi.

voici le problème, le rouge est mon activité qui est à l'arrière-plan tandis que le dialogue est au premier plan:

the red is my activity which is in the background while the dialogue is in the foreground

EDIT: j'ai essayé tout simplement pas à l'aide de finish() mais alors, mon activité peut être repris dans la pile d'applications dont je suis en train de les éviter.

86
demandé sur Girish Nair 2013-08-04 03:45:55

21 réponses

C'est ce qui est recommandé comme la droite solution:

la bonne solution (les crédits vont à Dan, CommonsWare et NeTeInStEiN) La visibilité du suivi de votre application par vous-même en utilisant Activité.onPause, de l'Activité.méthodes onResume. Conserver le statut "visibilité" dans certains autres de la classe. Les bons choix sont votre propre mise en œuvre de la Application ou un Service (il y a aussi quelques variantes de ce solution si vous souhaitez vérifier la visibilité de l'activité à partir du service).

exemple Implémenter la classe d'Application personnalisée (noter la méthode statique isActivityVisible ()):

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 d'application dans AndroidManifest.xml:

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

ajoutez unepause et unesume à chaque activité du projet (vous pouvez créer un ancêtre commun pour votre Activités si vous le souhaitez, mais si votre activité est déjà étendue de MapActivity / ListActivity etc. vous devez encore écrire ce qui suit à la main):

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

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

dans votre méthode finish() , vous voulez utiliser isActivityVisible() pour vérifier si l'activité est visible ou non. Vous pouvez également vérifier si l'Utilisateur a sélectionné une option ou non. Continuer lorsque les deux conditions sont remplies.

la source mentionne également deux erreurs solutions ... alors évitez de faire ça.

Source: stackoverflow

164
répondu But I'm Not A Wrapper Class 2017-05-23 12:26:27

si vous ciblez L'API de niveau 14 ou plus, vous pouvez utiliser android.App.Application.ActivityLifecycleCallbacks

public class MyApplication extends Application implements ActivityLifecycleCallbacks {
    private static boolean isInterestingActivityVisible;

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

        // Register to be notified of activity state changes
        registerActivityLifecycleCallbacks(this);
        ....
    }

    public boolean isInterestingActivityVisible() {
        return isInterestingActivityVisible;
    }

    @Override
    public void onActivityResumed(Activity activity) {
        if (activity instanceof MyInterestingActivity) {
             isInterestingActivityVisible = true;
        }
    }

    @Override
    public void onActivityStopped(Activity activity) {
        if (activity instanceof MyInterestingActivity) {
             isInterestingActivityVisible = false;
        }
    }

    // Other state change callback stubs
    ....
}
57
répondu Himanshu Likhyani 2014-07-24 13:57:50

C'est exactement la différence entre onPause et onStop événements de l'activité comme décrit dans la documentation de classe D'activité .

si je vous comprends bien, ce que vous voulez faire est d'appeler finish() de votre activité onStop pour y mettre fin. Voir l'image ci-jointe de activité Lifecycle Demo App . C'est ce qui se passe lorsque L'activité B est lancée à partir de L'activité A. Le l'ordre des événements est de bas en haut de sorte que vous pouvez voir que L'activité a onStop est appelée après que L'activité b onResume était déjà appelée.

Activity lifecycle demo

dans le cas où un dialogue est affiché, votre activité est atténuée en arrière-plan et seulement onPause est appelé.

9
répondu Muzikant 2016-09-27 13:54:53

deux solutions possibles:

1) Callbacks Du Cycle De Vie De L'Activité

utilisez une Application qui implémente ActivityLifecycleCallbacks et utilisez-la pour suivre les événements du cycle de vie des activités dans votre application. Notez que ActivityLifecycleCallbacks sont pour api Android > = 14. Pour l'api Android précédente, vous devrez l'implémenter vous-même dans toutes vos activités; -)

Utilisez Application lorsque vous devez partager / stocker des États à travers les activités.

2) Vérifier les informations du processus d'exécution

Vous pouvez vérifier l'état du processus en cours d'exécution avec cette classe RunningAppProcessInfo

récupération de la liste des processus en cours d'exécution avec ActivityManager.getRunningAppProcesses () et filtrer la liste des résultats pour vérifier RunningAppProcessInfo et vérifier son "importance"

7
répondu avianey 2013-08-27 06:33:56

activité::hasWindowFocus () vous renvoie le booléen dont vous avez besoin.

public class ActivityForegroundChecker extends TimerTask
{
    private static final long FOREGROUND_CHECK_PERIOD = 5000;
    private static final long FIRST_DELAY             = 3000;

    private Activity m_activity;
    private Timer    m_timer;

    public ActivityForegroundChecker (Activity p_activity)
    {
        m_activity = p_activity;
    }

    @Override
    public void run()
    {
        if (m_activity.hasWindowFocus() == true) {
            // Activity is on foreground
            return;
        }
        // Activity is on background.
    }

    public void start ()
    {
        if (m_timer != null) {
            return;
        }
        m_timer = new Timer();
        m_timer.schedule(this, FIRST_DELAY, FOREGROUND_CHECK_PERIOD);
    }

    public void stop ()
    {
        if (m_timer == null) {
            return;
        }
        m_timer.cancel();
        m_timer.purge();
        m_timer = null;
    }
}

voici un exemple de classe pour vérifier la visibilité de vos activités où que vous soyez.

rappelez-vous que si vous montrez un dialogue , le résultat sera faux puisque le dialogue aura la mise au point principale. À part cela, c'est très pratique et plus fiable que les solutions suggérées.

5
répondu Burak Day 2018-01-09 11:08:12

j'ai créer un projet sur github app-au premier plan-arrière-plan-écouter

qui utilise une logique très simple et fonctionne très bien avec tous les niveaux D'API android.

4
répondu kiran boghra 2015-08-06 10:07:54

Utiliser l'intervalle de temps entre pause et reprendre à partir du fond de déterminer s'il est éveillé d'arrière-plan

Dans Application Personnalisée

private static boolean isInBackground;
private static boolean isAwakeFromBackground;
private static final int backgroundAllowance = 10000;

public static void activityPaused() {
    isInBackground = true;
    final Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            if (isInBackground) {
                isAwakeFromBackground = true;
            }
        }
    }, backgroundAllowance);
    Log.v("activity status", "activityPaused");
}

public static void activityResumed() {
    isInBackground = false;
    if(isAwakeFromBackground){
        // do something when awake from background
        Log.v("activity status", "isAwakeFromBackground");
    }
    isAwakeFromBackground = false;
    Log.v("activity status", "activityResumed");
}

En Classe D'Activité De Base

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

@Override
protected void onPause() {
  super.onPause();
  MyApplication.activityPaused();
}
3
répondu Kit 2014-06-25 03:56:08

je pense que j'ai une meilleure solution. Parce que vous pouvez construire simplement mon application.activityResumed(); pour chaque Activité par une extension.

tout D'abord, vous devez créer (comme CyberneticTwerkGuruOrc)

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

ensuite, vous devez ajouter la classe D'Application à AndroidManifest.xml

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

ensuite, créer la classe ActivityBase

public class ActivityBase extends Activity {

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

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

enfin, quand vous créez une nouvelle activité, vous pouvez étend simplement par ActivityBase au lieu de L'activité.

public class Main extends ActivityBase {
    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }
}

pour moi, c'est une meilleure méthode parce que vous devez juste vous rappeler à propos de extend by ActivityBase. En outre, vous pouvez étendre votre fonction de base à l'avenir. Dans mon cas, j'ai ajouté des récepteurs pour mon service et des alertes sur le réseau dans une classe.

si vous voulez vérifier la visibilité de votre application, vous pouvez simplement appeler

MyApplication.isActivityVisible()
2
répondu EliaszKubala 2016-02-26 11:04:24

avez-vous essayé de ne pas appeler finish, et de mettre"android:noHistory=" true " dans le manifeste? cela permettra d'éviter l'activité d'aller à la pile.

1
répondu shaish 2013-08-20 23:41:41

je dois dire que votre flux de travail n'est pas D'une manière Android standard. Dans Android, vous n'avez pas besoin de finish() votre activité si vous voulez ouvrir une autre activité D'intention. Comme pour la commodité de l'utilisateur, Android permet à l'utilisateur d'utiliser "retour" pour aller à l'arrière de l'activité que vous avez ouvert pour votre application.

alors laissez le système arrêter votre activité et enregistrer tout ce qui est nécessaire lorsque votre activité est rappelée.

1
répondu Owen Zhao 2013-08-24 11:59:25

Je ne sais pas pourquoi personne n'a parlé de références partagées, pour L'activité A, définir une référence partagée comme cela (par exemple dans onPause ()):

SharedPreferences pref = context.getSharedPreferences(SHARED_PREF, 0);
SharedPreferences.Editor editor = pref.edit();
editor.putBoolean("is_activity_paused_a", true);
editor.commit();

je pense que c'est la façon fiable de suivre les activités visibilty.

1
répondu HZDI 2017-10-31 22:40:38

Si vous voulez savoir si toute l'activité de votre application est visible sur l'écran, vous pouvez faire quelque chose comme ceci:

public class MyAppActivityCallbacks implements Application.ActivityLifecycleCallbacks {
private Set<Class<Activity>> visibleActivities = new HashSet<>();

@Override
public void onActivityResumed(Activity activity) {
    visibleActivities.add((Class<Activity>) activity.getClass());
}

@Override
public void onActivityStopped(Activity activity) {
     visibleActivities.remove(activity.getClass());
}

public boolean isAnyActivityVisible() {
    return !visibleActivities.isEmpty();
}

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

@Override
public void onActivityStarted(Activity activity) {}

@Override
public void onActivityPaused(Activity activity) {}

@Override
public void onActivityDestroyed(Activity activity) {}

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

il suffit de créer un singleton de cette classe et de le régler dans votre instance D'Application comme ci-dessous:

class App extends Application{
     @Override
     public void onCreate() {
         registerActivityLifecycleCallbacks(myAppActivityCallbacks);
     }
}

alors vous pouvez utiliser la méthode isAnyActivityVisible () de votre instance MyAppActivityCallbacks partout!

1
répondu Vasil Stolyarchuk 2018-06-15 17:07:14

Enregistrer un drapeau si vous êtes en pause ou reprise. Si vous êtes repris, cela signifie que vous êtes au premier plan

boolean  isResumed = false;

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

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

private void finishIfForeground() {
  if (isResumed) {
    finish();
  }
}
0
répondu yoah 2013-08-26 16:07:09

une solution possible pourrait être de mettre un drapeau tout en montrant la boîte de dialogue système et puis dans la méthode onStop du cycle de vie de l'activité, vérifier le drapeau, si vrai, terminer l'activité.

par exemple, si la boîte de dialogue du système est déclenchée par un buttonclick, alors l'écouteur onclick pourrait être comme

private OnClickListener btnClickListener = new OnClickListener() {

    @Override
    public void onClick(View v) {           
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_SEND);
        intent.setType("text/plain");
        CheckActivity.this.startActivity(Intent.createChooser(intent, "Complete action using"));
        checkFlag = true;  //flag used to check

    }
};

et en haut d'activité:

@Override
protected void onStop() {
    if(checkFlag){
        finish();
    }
    super.onStop();
}
0
répondu Diya 2013-08-27 07:15:27

pourquoi ne pas utiliser des émissions pour cela? la deuxième activité (celle qui doit être mise en place) peut envoyer une diffusion locale comme celle-ci:

//put this in onCreate(..) or any other lifecycle method that suits you best
//notice the string sent to the intent, it will be used to register a receiver!
Intent result = new Intent("broadcast identifier");
result.putString("some message");//this is optional
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(result);

alors écrivez un récepteur simple dans l'activité splash:

//this goes on the class level (like a class/instance variable, not in a method) of your splash activity:
private BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        //kill activity here!!!
        //mission accomplished!
    }
};

et enregistrez votre nouveau récepteur avec le gestionnaire local de diffusion pour écouter l'émission de votre deuxième activité:

//notice the string sent to the intent filter, this is where you tell the BroadcastManager which broadcasts you want to listen to!
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(receiver, new IntentFilter("broadcast identifier"));

notez que vous pouvez utiliser une constante ou une ressource de chaîne de caractères pour "la diffusion de l'identificateur de" chaîne de caractères.

0
répondu 2013-08-27 12:55:17

si vous utilisez finish() juste pour éviter la nouvelle application pour commencer dans la pile (tâche) de votre application, vous pouvez utiliser le drapeau Intent.FLAG_ACTIVITY_NEW_TASK , lors du démarrage de la nouvelle application et ne pas appeler finish() du tout. Selon la documentation , c'est le drapeau à utiliser pour implémenter un comportement de type "lanceur".

// just add this line before you start an activity
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
0
répondu sergej shafarenka 2013-08-27 16:06:21

cela peut être réalisé de manière efficace en utilisant L'Application .ActivityLifecycleCallbacks

par exemple, prenons le nom de la classe D'activité comme ProfileActivity permet de savoir si elle est en premier plan ou en arrière-plan

tout d'abord, nous devons créer notre classe d'application en étendant Classe d'Application

qui met en œuvre

de l'Application.ActivityLifecycleCallbacks

permet D'être ma classe D'Application comme suit

Classe D'Application

public class AppController extends Application implements Application.ActivityLifecycleCallbacks {


private boolean activityInForeground;

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

//register ActivityLifecycleCallbacks  

    registerActivityLifecycleCallbacks(this);

}



public static boolean isActivityVisible() {
    return activityVisible;
}

public static void activityResumed() {
    activityVisible = true;
}

public static void activityPaused() {
    activityVisible = false;
}

private static boolean activityVisible;

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

}

@Override
public void onActivityStarted(Activity activity) {

}

@Override
public void onActivityResumed(Activity activity) {
    //Here you can add all Activity class you need to check whether its on screen or not

    activityInForeground = activity instanceof ProfileActivity;
}

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

}

public boolean isActivityInForeground() {
    return activityInForeground;
}
}

dans la classe ci-dessus, il y a une commande prioritaire onActivityResumed de ActivityLifecycleCallbacks

 @Override
public void onActivityResumed(Activity activity) {
    //Here you can add all Activity class you need to check whether its on screen or not

    activityInForeground = activity instanceof ProfileActivity;
}

où toutes les instances d'activité qui sont actuellement affichée à l'écran peut être trouvé, vérifiez si Votre Activité est sur l'Écran ou pas par la méthode ci-dessus.

enregistrez votre classe de demande dans le manifeste.xml

<application
    android:name=".AppController" />

pour vérifier que L'activité météorologique est au premier plan ou en arrière-plan, conformément à la solution ci-dessus, appelez la méthode suivante sur les endroits que vous devez vérifier

AppController applicationControl = (AppController) getApplicationContext();
    if(applicationControl.isActivityInForeground()){
     Log.d("TAG","Activity is in foreground")
    }
    else
    {
      Log.d("TAG","Activity is in background")
    }
0
répondu Ramz 2016-03-08 13:30:13

utilisez ces méthodes à l'intérieur d'un Activity .



isDestroyed()

ajouté dans Api 17

Renvoie true si l'appel final onDestroy() a été fait sur le Activité, donc cette instance est maintenant morte.

isFinishing()

ajouté dans Api 1

Vérifier si cette activité est en cours de finition, soit parce que vous avez appelé finish() sur elle ou quelqu'un d'autre a demandé qu'il a fini. Ceci est souvent utilisé dans onPause() pour déterminer si l'activité est simplement une pause ou la fin complète.



À Partir De Fuites De Mémoire Documentation

une erreur courante avec AsyncTask est de capturer une référence forte à l'hôte Activity (ou Fragment ):

class MyActivity extends Activity {
  private AsyncTask<Void, Void, Void> myTask = new AsyncTask<Void, Void, Void>() {
    // Don't do this! Inner classes implicitly keep a pointer to their
    // parent, which in this case is the Activity!
  }
}

C'est un problème parce que AsyncTask peut facilement survivre au parent Activity , par exemple si un changement de configuration se produit pendant que la tâche est en cours d'exécution.

la bonne façon de faire cela est de faire de votre tâche une classe static , ce qui ne ne pas capturer le parent, et en tenant un faible référence à l'hôte Activity :

class MyActivity extends Activity {
  static class MyTask extends AsyncTask<Void, Void, Void> {
    // Weak references will still allow the Activity to be garbage-collected
    private final WeakReference<MyActivity> weakActivity;

    MyTask(MyActivity myActivity) {
      this.weakActivity = new WeakReference<>(myActivity);
    }

    @Override
    public Void doInBackground(Void... params) {
      // do async stuff here
    }

    @Override
    public void onPostExecute(Void result) {
      // Re-acquire a strong reference to the activity, and verify
      // that it still exists and is active.
      MyActivity activity = weakActivity.get();
      if (activity == null
          || activity.isFinishing()
          || activity.isDestroyed()) {
        // activity is no longer valid, don't do anything!
        return;
      }

      // The activity is still valid, do main-thread stuff here
    }
  }
}
0
répondu Sanket Berde 2017-03-15 05:20:58

Voici une solution utilisant la classe Application .

public class AppSingleton extends Application implements Application.ActivityLifecycleCallbacks {

private WeakReference<Context> foregroundActivity;


@Override
public void onActivityResumed(Activity activity) {
    foregroundActivity=new WeakReference<Context>(activity);
}

@Override
public void onActivityPaused(Activity activity) {
    String class_name_activity=activity.getClass().getCanonicalName();
    if (foregroundActivity != null && 
            foregroundActivity.get().getClass().getCanonicalName().equals(class_name_activity)) {
        foregroundActivity = null;
    }
}

//............................

public boolean isOnForeground(@NonNull Context activity_cntxt) {
    return isOnForeground(activity_cntxt.getClass().getCanonicalName());
}

public boolean isOnForeground(@NonNull String activity_canonical_name) {
    if (foregroundActivity != null && foregroundActivity.get() != null) {
        return foregroundActivity.get().getClass().getCanonicalName().equals(activity_canonical_name);
    }
    return false;
}
}

, Vous pouvez simplement l'utiliser comme suit,

((AppSingleton)context.getApplicationContext()).isOnForeground(context_activity);

Si vous avez une référence à l'Activité requis ou en utilisant le nom canonique de l'Activité, vous pouvez savoir si elle est au premier plan ou non. Cette solution n'est peut-être pas infaillible. Donc vos commentaires sont vraiment les bienvenus.

0
répondu TMtech 2017-09-29 11:14:54

est-ce que Activity.onWindowFocusChanged(boolean hasFocus) serait utile ici? Cela, plus un drapeau de classe, quelque chose comme isFocused que onWindowFocusChanged ensembles, serait un moyen facile de dire à tout moment dans votre activité si elle est ciblée ou non. En lisant le docs, il semble qu'il serait correctement placé "false" dans toute situation où l'activité n'est pas directement dans le "premier plan" physique, comme si une boîte de dialogue est affichée ou le plateau de notification est tiré vers le bas.

Exemple:

boolean isFocused;
@Override
void onWindowFocusChanged (boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    isFocused = hasFocus;
}

void someMethod() {
    if (isFocused) {
        // The activity is the foremost object on the screen
    } else {
        // The activity is obscured or otherwise not visible
    }
}
0
répondu InsanityOnABun 2017-11-16 19:05:17

j'avais l'habitude de faire, comme,

si l'activité n'est pas au premier plan

getIntent ()

renverra null. : = P

-3
répondu Jacob Abraham 2014-06-23 14:37:24