Jak sprawdzić, czy aktywność jest na pierwszym planie, czy w widocznym tle?

104

Mam ekran powitalny na zegarze. Mój problem polega na tym, że przed wykonaniem finish()czynności muszę sprawdzić, czy rozpoczęło się kolejne działanie, ponieważ wyskakuje systemowe okno dialogowe i chcę tylko finish(); po wybraniu przez użytkownika opcji w oknie dialogowym?

Wiem, że jest wiele pytań dotyczących tego, jak sprawdzić, czy twoja aktywność jest na pierwszym planie, ale nie wiem, czy to pozwala również na okna dialogowe u góry działania.

Oto problem, czerwony to moja aktywność, która jest w tle, podczas gdy dialog jest na pierwszym planie:

czerwony to moja aktywność, która jest w tle, podczas gdy dialog jest na pierwszym planie

EDYCJA: Próbowałem po prostu nie używać, finish()ale wtedy moja aktywność może wrócić do stosu aplikacji, których staram się uniknąć.

Nacięcie
źródło
Może mieć znaczenie: stackoverflow.com/questions/4414171/…
jarmod
Aby wyjaśnić, chcesz uruchomić selektor intencji i poczekać, aż aplikacja zakończy się (), aż użytkownik wybierze jedną z opcji? Wygląda na to, że potrzebujesz Intent.createChooser () i startActivityForResult (), a następnie finish () po otrzymaniu wyniku.
alanv
możliwy duplikat Sprawdzania, czy aplikacja na Androida działa w tle
Douglas Nassif Roma Junior
ProcessLifecycleOwner to najnowsze rozwiązanie
SR

Odpowiedzi:

189

Oto, co jest zalecane jako właściwe rozwiązanie:

Właściwe rozwiązanie (kredyty trafiają do Dan, CommonsWare i NeTeInStEiN) Samodzielnie śledź widoczność swojej aplikacji za pomocą metod Activity.onPause, Activity.onResume. Przechowuj stan „widoczności” w innej klasie. Dobrym wyborem jest własna implementacja Aplikacji lub Usługi (istnieje również kilka odmian tego rozwiązania, jeśli chcesz sprawdzić widoczność aktywności w serwisie).

Przykład Implementuj niestandardową klasę aplikacji (zwróć uwagę na metodę statyczną 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;
}

Zarejestruj klasę aplikacji w AndroidManifest.xml:

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

Dodaj onPause i onResume do każdego działania w projekcie (możesz utworzyć wspólnego przodka dla swoich działań, jeśli chcesz, ale jeśli Twoja aktywność jest już rozszerzona z MapActivity / ListActivity itp., Nadal musisz ręcznie napisać poniższy tekst) :

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

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

W swojej finish()metodzie chcesz użyć, isActivityVisible()aby sprawdzić, czy aktywność jest widoczna, czy nie. Tam możesz również sprawdzić, czy użytkownik wybrał opcję, czy nie. Kontynuuj, gdy oba warunki zostaną spełnione.

Źródło wspomina również o dwóch błędnych rozwiązaniach ... więc unikaj tego.

Źródło: stackoverflow

Ale nie jestem klasą opakowującą
źródło
Jest jeden mały moment między zakończeniem a rozpoczęciem aktywności i
myślę, że
28
To nie działa niezawodnie. Może wystąpić następująca sytuacja: Wznów A Wznów B Wstrzymaj A. Teraz activityVisible ma wartość false, podczas gdy aplikacja jest widoczna. Być może używasz licznika widoczności: visibleCounter ++ w onResume i visibleCounter - w onPause.
Joris Weimar
4
Zgodził się z Jorisem Weimarem, że nie jest to niezawodne rozwiązanie. Jeden scenariusz, jeśli użytkownik rozebrany panel powiadomień, a następnie ani onPause, onStopani onResumewydarzeniem jest tzw. Więc co zrobisz, jeśli żadne z tych wydarzeń nie zostanie zwolnione ?!
1
W rzeczywistości żadna z pozostałych odpowiedzi również nie działa w 100%.
2
Jeśli aplikacja ma więcej niż jedno działanie, ten schemat nie zadziała. Zastąp przynajmniej licznikami
ruX
70

Jeśli kierujesz się na poziom interfejsu API 14 lub wyższy, możesz użyć 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
    ....
}
silvermouse
źródło
18
Możesz to po prostu zrobić w wywołaniach zwrotnych cyklu życia zwykłej aktywności (onResume (), onStop ()) też powiedziałbym.
Daniel Wilson,
5
@DanielWilson Myślę, że nie chodzi o budowanie systemu do robienia czegoś, co już istnieje. IMHO powinna to być akceptowana odpowiedź.
Jeffrey Blattman
26

UPD : zaktualizowano do stanu Lifecycle.State.RESUMED. Dzięki za to @htafoya .

W 2019 z pomocą nowej biblioteki wsparcia 28+lub AndroidX możesz po prostu użyć:

val isActivityInForeground = activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)

Możesz przeczytać więcej w dokumentacji, aby zrozumieć, co wydarzyło się pod maską.

Alex Misiulia
źródło
2
Nie bardzo, prawdopodobnie lepiej jest umieścić activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED) lub ROZPOCZĄĆ. INITIALIZEDnie gwarantuje, że jest na pierwszym planie.
htafoya
11

Activity :: hasWindowFocus () zwraca wartość logiczną, której potrzebujesz.

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

Oto przykładowe zajęcia, aby sprawdzić widoczność swoich działań z dowolnego miejsca.

Pamiętaj, że jeśli pokażesz okno dialogowe , wynik będzie fałszywy, ponieważ okno dialogowe będzie miało główny fokus. Poza tym jest naprawdę poręczny i bardziej niezawodny niż sugerowane rozwiązania.

Burak Day
źródło
1
Dziękuję za zmianę odpowiedzi @Burak Day, w rzeczywistości jest to teraz odpowiedź
Nick
To nie działa, wolałbym raczej użyć właściwości boolowskiej w klasie, ustawionej na true w OnResume i ustawionej na false w OnPause ();
Chandler,
@ Chandler, jaki jest dokładny problem z tym kodem? Również która wersja?
Dzień Burak
@Chandler również, co jeśli nie masz dostępu do metod cyklu życia działania. Weź pod uwagę, że właśnie sprawdzasz widoczność działania w bibliotece.
Dzień Burak
Prawdziwym problemem związanym z tą odpowiedzią jest to, że NIE działa, activity.hasWindowFocus jest true, nie może zagwarantować, że aktywność będzie między stanem onResume i onPause. Wolałbym raczej dodać właściwość bool isResumed w tym działaniu, ręcznie ustawić wartość i dodać metodę get.
Chandler,
10

To jest dokładnie różnica między onPausei onStopwydarzenia z działalności opisane w dokumentacji klasy aktywny .

Jeśli dobrze Cię rozumiem, to co chcesz zrobić, to zadzwonić finish()ze swojej działalności, onStopaby ją zakończyć. Zobacz załączony obraz aplikacji Activity Lifecycle Demo . Tak to wygląda, gdy aktywny B jest uruchamiany z działalności A. Kolejność zdarzeń jest od dołu do góry, dzięki czemu można zobaczyć, że aktywność na onStopnazywa po Działalność B onResumejuż została wywołana.

Demo cyklu życia działania

W przypadku wyświetlenia okna dialogowego Twoja aktywność jest wygaszona w tle i tylko onPausejest wywoływana.

Muzikant
źródło
7

Dwa możliwe rozwiązania:

1) Wywołania zwrotne cyklu życia działania

Użyj aplikacji, która implementuje ActivityLifecycleCallbacks i użyj jej do śledzenia zdarzeń cyklu życia działań w aplikacji. Zwróć uwagę, że ActivityLifecycleCallbacks są dla interfejsu API systemu Android> = 14. W przypadku poprzedniego interfejsu API systemu Android musisz zaimplementować go samodzielnie we wszystkich swoich działaniach ;-)

Użyj aplikacji, gdy chcesz udostępniać / przechowywać stany w różnych działaniach.

2) Sprawdź, czy są uruchomione informacje o procesie

Możesz sprawdzić stan uruchomionego procesu za pomocą tej klasy RunningAppProcessInfo

Pobierz listę uruchomionych procesów za pomocą ActivityManager.getRunningAppProcesses () i przefiltruj listę wyników, aby sprawdzić żądane RunningAppProcessInfo i sprawdź jego „ważność”

avianey
źródło
3

Użyj przerwy czasowej między wstrzymaniem a wznowieniem z tła, aby określić, czy jest wybudzony z tła

W aplikacji niestandardowej

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

W klasie BaseActivity

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

@Override
protected void onPause() {
  super.onPause();
  MyApplication.activityPaused();
}
Zestaw
źródło
3

Myślę, że mam lepsze rozwiązanie. Ponieważ możesz wbudować po prostu MyApplication.activityResumed (); do każdego działania o jeden zakres.

Najpierw musisz stworzyć (jak 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;
}

Następnie musisz dodać klasę Application do AndroidManifest.xml

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

Następnie utwórz klasę ActivityBase

public class ActivityBase extends Activity {

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

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

Wreszcie, kiedy tworzysz nową aktywność, możesz ją po prostu rozszerzyć o ActivityBase zamiast Activity.

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

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

Dla mnie to lepsza metoda, bo trzeba tylko pamiętać o rozszerzeniu o ActivityBase. Ponadto w przyszłości możesz rozszerzyć swoją podstawową funkcję. W moim przypadku dodałem odbiorniki do mojej usługi i alerty o sieci w jednej klasie.

Jeśli chcesz sprawdzić widoczność swojej aplikacji, możesz po prostu zadzwonić

MyApplication.isActivityVisible()
Eliasz Kubala
źródło
Co się stanie, jeśli potrzebuję działań, aby przedłużyć AppCombatActivity?
winklerrr
2

Można to osiągnąć w efektywny sposób przy użyciu Application.ActivityLifecycleCallbacks

Na przykład, weźmy nazwę klasy Activity jako ProfileActivity pozwala sprawdzić, czy jest na pierwszym planie, czy w tle

najpierw musimy stworzyć naszą klasę aplikacji, rozszerzając Application Class

które implementuje

Application.ActivityLifecycleCallbacks

Niech moja klasa aplikacji będzie następująca

Klasa aplikacji

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

w powyższej klasie jest methord przesłanianie onActivityResumed z 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;
}

gdzie można znaleźć wszystkie instancje aktywności, które są aktualnie wyświetlane na ekranie, po prostu sprawdź, czy Twoja aktywność jest na ekranie, czy nie, za pomocą powyższej metody.

Zarejestruj klasę aplikacji w pliku manifest.xml

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

Aby sprawdzić pogodę Aktywność jest na pierwszym planie lub w tle, zgodnie z powyższym rozwiązaniem, wywołaj następującą metodę w miejscach, które musisz sprawdzić

AppController applicationControl = (AppController) getApplicationContext();
    if(applicationControl.isActivityInForeground()){
     Log.d("TAG","Activity is in foreground")
    }
    else
    {
      Log.d("TAG","Activity is in background")
    }
Ramz
źródło
1

Jeśli chcesz wiedzieć, czy jakakolwiek aktywność Twojej aplikacji jest widoczna na ekranie, możesz zrobić coś takiego:

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

Po prostu utwórz singletona tej klasy i ustaw go w swojej instancji Application, jak poniżej:

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

Następnie możesz użyć metody isAnyActivityVisible () swojej instancji MyAppActivityCallbacks wszędzie!

Wasil Stolyarchuk
źródło
0

Czy próbowałeś nie wywoływać finish i umieszczać w manifeście „android: noHistory =„ true ”? Zapobiegnie to przeniesieniu aktywności na stos.

shaish
źródło
0

Muszę powiedzieć, że twój przepływ pracy nie jest w standardowy sposób na Androida. W Androidzie nie musisz wykonywać finish()swojej aktywności, jeśli chcesz otworzyć inną aktywność z Intent. Jeśli chodzi o wygodę użytkownika, system Android umożliwia użytkownikowi użycie klawisza „Wstecz”, aby cofnąć się z otwartej czynności w aplikacji.

Po prostu pozwól systemowi zatrzymać Twoją aktywność i zapisz wszystko, co jest potrzebne, gdy Twoja aktywność zostanie odwołana.

Owen Zhao
źródło
3
„ale to nie jest android”, więc odpowiedzi są męczące i nie odpowiadają na zadane pytanie. ponadto istnieją ważne powody, aby zakończyć (); - na przykład można sobie wyobrazić, że powrót do niej po podjęciu działania jest bezcelowy. innymi słowy, czy myślisz, że umieścili tam finish () dla zabawy? pozostanie na stosie jest dokładnie tym, czego osoba zadająca pytanie chciała uniknąć
Lassi Kinnunen,
„ale to nie jest android”, więc odpowiedzi są męczące i nie odpowiadają na zadane pytanie. Twoja pochwała była niesprawiedliwa. Chociaż zaznaczyłem, że to nie jest sposób na Androida, zamiast niczego podałem odpowiedź po tym zdaniu. Po prostu nie podałem odpowiedzi w kodzie, ponieważ było to niepotrzebne. Więc było to niesprawiedliwe, mówiąc, że nie odpowiedziałem na pytanie w pierwszej kolejności.
Owen Zhao
0

Zapisz flagę, jeśli jesteś wstrzymany lub wznowiony. Jeśli zostaniesz wznowiony, oznacza to, że jesteś na pierwszym planie

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();
  }
}
yoah
źródło
0

Jednym z możliwych rozwiązań może być ustawienie flagi podczas wyświetlania okna dialogowego systemu, a następnie w metodzie onStop cyklu życia działania sprawdzenie flagi, jeśli prawda, zakończenie działania.

Na przykład, jeśli systemowe okno dialogowe jest uruchamiane przez jakieś kliknięcie przycisku, wówczas odbiornik onclick może wyglądać tak

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

    }
};

i po zakończeniu działalności:

@Override
protected void onStop() {
    if(checkFlag){
        finish();
    }
    super.onStop();
}
Diya
źródło
0

Dlaczego nie wykorzystać do tego transmisji? druga czynność (ta, która musi być włączona) może wysyłać lokalną transmisję w następujący sposób:

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

następnie napisz prosty odbiornik w ramach działania 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!
    }
};

i zarejestruj swój nowy odbiornik w LocalBroadcastManager, aby słuchać transmisji z drugiej czynności:

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

PAMIĘTAJ, że można użyć stałej lub łańcuchowej dla ciągu „identyfikatora emisji”.


źródło
Dla lepszej skuteczności reklam bezpieczeństwa użyj LocalBroadcastManagertutaj
Alexander Farber
0

Jeśli używasz finish()tylko w celu uniknięcia uruchamiania nowej aplikacji na stosie (zadaniu) swojej aplikacji, możesz użyć Intent.FLAG_ACTIVITY_NEW_TASKflagi podczas uruchamiania nowej aplikacji i nie wywoływać finish()w ogóle. Zgodnie z dokumentacją jest to flaga, która ma być używana do implementacji zachowania w stylu „programu uruchamiającego”.

// just add this line before you start an activity
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
sergej shafarenka
źródło
0

Użyj tych metod wewnątrz pliku Activity.

isDestroyed()

Dodany w Api 17
Zwraca wartość true, jeśli ostatnie wywołanie onDestroy () zostało wykonane w działaniu, więc ta instancja jest teraz martwa.

isFinishing()

Dodane w Api 1
Sprawdź, czy ta czynność jest w trakcie kończenia, ponieważ wywołałeś na niej finish () lub ktoś inny zażądał jej zakończenia. Jest to często używane w onPause () do określenia, czy czynność jest po prostu wstrzymywana, czy całkowicie kończy.


Z dokumentacji wycieków pamięci

Częstym błędem AsyncTaskjest uchwycenie silnego odniesienia do hosta Activity(lub 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!
  }
}

Jest to problem, ponieważ AsyncTaskmoże łatwo przeżyć rodzica Activity, na przykład jeśli zmiana konfiguracji nastąpi podczas działania zadania.

Właściwy sposób to uczynić swoje zadanie staticklasą, która nie wychwytuje rodzica, i utrzymywać słabe odniesienie do hosta 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
    }
  }
}
Sanket Berde
źródło
0

Oto rozwiązanie wykorzystujące Applicationklasę.

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

Możesz go po prostu użyć w następujący sposób,

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

Jeśli masz odniesienie do wymaganego działania lub używając kanonicznej nazwy działania, możesz dowiedzieć się, czy jest ono na pierwszym planie, czy nie. To rozwiązanie może nie być niezawodne. Dlatego Twoje komentarze są naprawdę mile widziane.

TMtech
źródło
0

Nie wiem, dlaczego nikt nie mówił o sharedPreferences, dla Działania A, ustawiając SharedPreference w ten sposób (na przykład w onPause ()):

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

Myślę, że jest to niezawodny sposób śledzenia widoczności działań.

HZDI
źródło
0

Przydałby Activity.onWindowFocusChanged(boolean hasFocus)się tutaj? To, plus flaga na poziomie klasy, coś w isFocusedtym rodzaju onWindowFocusChanged, byłoby łatwym sposobem na stwierdzenie w dowolnym momencie twojej aktywności, czy jest skupiona, czy nie. Po przeczytaniu dokumentów wygląda na to, że poprawnie ustawiłoby to „fałsz” w każdej sytuacji, w której działanie nie znajduje się bezpośrednio na fizycznym „pierwszym planie”, na przykład w przypadku wyświetlania okna dialogowego lub opuszczania zasobnika powiadomień.

Przykład:

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
    }
}
InsanityOnABun
źródło
0

Jeśli używasz EventBus , jest to metoda wywoływana, hasSubscriberForEventktórej można użyć do sprawdzenia, czy Activityjest fokus.

Kris B
źródło
-3

Lubiłem

jeśli działanie nie jest na pierwszym planie

getIntent ()

zwróci wartość null. : = P

Jacob Abraham
źródło