How to check if activity is in foreground or in visible background?
Solution 1
This is what is recommended as the right solution:
The right solution (credits go to Dan, CommonsWare and NeTeInStEiN) Track visibility of your application by yourself using Activity.onPause, Activity.onResume methods. Store "visibility" status in some other class. Good choices are your own implementation of the Application or a Service (there are also a few variations of this solution if you'd like to check activity visibility from the service).
Example Implement custom Application class (note the isActivityVisible() static method):
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;
}
Register your application class in AndroidManifest.xml:
<application
android:name="your.app.package.MyApplication"
android:icon="@drawable/icon"
android:label="@string/app_name" >
Add onPause and onResume to every Activity in the project (you may create a common ancestor for your Activities if you'd like to, but if your activity is already extended from MapActivity/ListActivity etc. you still need to write the following by hand):
@Override
protected void onResume() {
super.onResume();
MyApplication.activityResumed();
}
@Override
protected void onPause() {
super.onPause();
MyApplication.activityPaused();
}
In your finish()
method, you want to use isActivityVisible()
to check if the activity is visible or not. There you can also check if the user has selected an option or not. Continue when both conditions are met.
The source also mentions two wrong solutions...so avoid doing that.
Source: stackoverflow
Solution 2
If targeting API level 14 or above, one can use 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
....
}
Solution 3
UPD: updated to state Lifecycle.State.RESUMED
. Thanks to @htafoya for that.
In 2019 with help of new support library 28+
or AndroidX you can simply use:
val isActivityInForeground = activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)
You can read more in the documenation to understand what happened under the hood.
Solution 4
Activity::hasWindowFocus() returns you the boolean you need.
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;
}
}
Here is an example class to check your activites' visibility from wherever you are.
Remember that if you show a dialog, the result will be false since the dialog will have the main focus. Other than that it's really handy and more reliable than suggested solutions.
Solution 5
That's exactly the difference between onPause
and onStop
events of the activity as described in the Activity class documentation.
If I understand you correctly, what you want to do is call finish()
from your activity onStop
to terminate it.
See the attached image of the Activity Lifecycle Demo App. This is how it looks like when Activity B is launched from Activity A.
The order of events is from bottom to top so you can see that Activity A onStop
is called after Activity B onResume
was already called.
In case a dialog is shown your activity is dimmed in the background and only onPause
is called.
Related videos on Youtube
Nick
Web dev is my jam, though I also dabble in Android and iOS native development. Run my own development firm and have been doing web for nearly 10 years now
Updated on April 30, 2021Comments
-
Nick about 3 years
I have a splash screen on a timer. My problem is that before I
finish()
my activity I need to check that the next activity has started because a system dialogue box pops-up and I only want tofinish()
; once the user has selected an option from the dialogue box?I know that there are many questions on how to see if your activity is in the foreground but I do not know if this allows for dialogue boxes on top of the activity too.
Here is the problem, the red is my activity which is in the background while the dialogue is in the foreground:
EDIT: I have tried just not using
finish()
but then my activity can be gone back to in the stack of applications which I am trying to avoid.-
jarmod over 10 yearsMay be relevant: stackoverflow.com/questions/4414171/…
-
alanv over 10 yearsTo clarify, you want to launch an intent chooser and wait for your app to finish() until after the user has tapped one of the choices? It sounds like you need Intent.createChooser() and startActivityForResult() followed by finish() when the result is received.
-
Douglas Nassif Roma Junior about 9 yearspossible duplicate of Checking if an Android application is running in the background
-
S.R about 5 yearsProcessLifecycleOwner is the newest solution
-
Nick over 2 years@AlexMisiulia No, I'll let the votes do the talking - if your answer gets more votes I'll be happy to change the accepted answer.
-
Alex Misiulia over 2 years@Nick, I got your point. But the problem is that accepted answer is buggy as mentioned in comment to the answer and will work incorrectly for some cases. And more people will make mistakes and loose their time. But anyway, this is your choice)
-
-
sagus_helgy almost 10 yearsThere is one little moment between finish and start activity and i thin need to add some delay and counter
-
Lassi Kinnunen about 9 years"buu this is not the android" way answers are tiresome and don't answer the question posed in the first place. furthermore, there are valid reasons to finish(); - for example it's conceivable that going back to it once the action has taken hold serves no purpose whatsoever. in other words, do you think they put finish() in there for fun? it staying on the stack is exactly what the question asker wanted to avoid
-
Joris Weimar about 9 yearsThis doesn't work reliably. You might have the following situation: Resume A Resume B Pause A. Now activityVisible is false whereas the application is visible. Perhaps you use a visibility counter: visibleCounter ++ in onResume and visibleCounter -- in onPause.
-
Admin almost 9 yearsAgreed with Joris Weimar that this is not a foolproof solution. One scenario is if the user pulled down the notification panel, then neither the
onPause
,onStop
, nor theonResume
event is called. So what do you do then if none of these events are fired?! -
Admin almost 9 yearsIn fact, none of the other answers work 100% either.
-
Alexander Farber over 8 yearsFor better security ad efficiency use
LocalBroadcastManager
here -
Daniel Wilson over 8 yearsYou could just do this in the regular activity lifecycle callbacks (onResume(), onStop()) too I would say.
-
ruX about 8 yearsIf app has more than one Activity this scheme won't work. Replace with counters at least
-
winklerrr about 7 yearsWhat if I need my Activities to extend the AppCombatActivity?
-
David Berry almost 7 yearsThis also doesn't work in the Android N split view case. One or the other of the activities will be paused, but visible.
-
Burak Day over 6 yearsCase: As a library, you want to unregister your sensorlistener when the activity of a project, which imported you, is on background. Solution: Not approved since you can't control activities.
-
Nick over 6 yearsThank you for amending the answer @Burak Day, it is actually an answer now
-
Chandler over 5 yearsThis does not work, I would rather use a boolean property in the class, set to true in OnResume, and set to false in OnPause();
-
Burak Day over 5 years@Chandler what's the exact issue you are having with this code? Also which version?
-
Burak Day over 5 years@Chandler also, what if you don't have access to activity lifecycle methods. Consider you are just checking activity's visibility from a library.
-
Chandler over 5 yearsThe real problem of this answer is it does NOT work, activity.hasWindowFocus is true can not guarantee the activity is between onResume and onPause state. I would rather recommend add an bool isResumed property in that activity, manually set the value and add a get method.
-
Jeffrey Blattman about 5 years@DanielWilson I think the point it is not to build a system for doing something where one already exists. IMHO this should be the accepted answer.
-
htafoya almost 5 yearsNot really, probably it is better to place
activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)
or STARTED.INITIALIZED
doesn't guarantee that it is in foreground. -
Owen Zhao over 3 years"buu this is not the android" way answers are tiresome and don't answer the question posed in the first place. Your commend was unfair. Although I pointed it out this was not Android way, I gave the answer after this sentence instead of nothing. I just didn't give the answer in code as that was unnecessary. So it was unfair saying I didn't answer the question in the first place.
-
Tyler over 3 yearsThis is great for checking if any of our activities are open. Far better than writing code in each one and risking missing something. Reliable and simple. Thanks!
-
Cactusroot almost 3 years@Chandler onResule is called slightly BEFORE the activity is turned visible.
-
Cactusroot almost 3 yearsThis answer should be the accepted one. onResume() is called before the activity is visible.
-
Akito over 2 yearsProject does not seem to be maintained, anymore.
-
Kris B over 2 yearsI don't think there is much to maintain since it does one specific thing. It still works though.
-
Raphael C about 2 yearsI think this is a nice solution, although why the need to keep a set of the activity classes? why not simply use a counter and increase/decrease it on resume/paused, and then check if == 0?