Checking if an Android application is running in the background
By background, I mean none of the application's activities are currently visible to the user?
There are few ways to detect whether your application is running in the background, but only one of them is completely reliable:
-
The right solution (credits go to Dan, CommonsWare and NeTeInStEiN)
Track visibility of your application by yourself usingActivity.onPause
,Activity.onResume
methods. Store "visibility" status in some other class. Good choices are your own implementation of theApplication
or aService
(there are also a few variations of this solution if you'd like to check activity visibility from the service).
Example
Implement customApplication
class (note theisActivityVisible()
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
andonResume
to everyActivity
in the project (you may create a common ancestor for your Activities if you'd like to, but if your activity is already extended fromMapActivity
/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(); }
Update
ActivityLifecycleCallbacks were added in API level 14 (Android 4.0). You can use them to track whether an activity of your application is currently visible to the user. Check Cornstalks' answer below for the details. -
The wrong one
I used to suggest the following solution:You can detect currently foreground/background application with
ActivityManager.getRunningAppProcesses()
which returns a list ofRunningAppProcessInfo
records. To determine if your application is on the foreground checkRunningAppProcessInfo.importance
field for equality toRunningAppProcessInfo.IMPORTANCE_FOREGROUND
whileRunningAppProcessInfo.processName
is equal to your application package name.Also if you call
ActivityManager.getRunningAppProcesses()
from your application UI thread it will return importanceIMPORTANCE_FOREGROUND
for your task no matter whether it is actually in the foreground or not. Call it in the background thread (for example viaAsyncTask
) and it will return correct results.While this solution may work (and it indeed works most of the time) I strongly recommend to refrain from using it. And here's why. As Dianne Hackborn wrote:
These APIs are not there for applications to base their UI flow on, but to do things like show the user the running apps, or a task manager, or such.
Yes there is a list kept in memory for these things. However, it is off in another process, managed by threads running separately from yours, and not something you can count on (a) seeing in time to make the correct decision or (b) have a consistent picture by the time you return. Plus the decision about what the "next" activity to go to is always done at the point where the switch is to happen, and it is not until that exact point (where the activity state is briefly locked down to do the switch) that we actually know for sure what the next thing will be.
And the implementation and global behavior here is not guaranteed to remain the same in the future.
I wish I had read this before I posted an answer on the SO, but hopefully it's not too late to admit my error.
Another wrong solution
Droid-Fu library mentioned in one of the answers usesActivityManager.getRunningTasks
for itsisApplicationBroughtToBackground
method. See Dianne's comment above and don't use that method either.
GOOGLE SOLUTION - not a hack, like previous solutions. Use ProcessLifecycleOwner
Kotlin:
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
}
}
Java:
public class ArchLifecycleApp extends Application implements LifecycleObserver {
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onAppBackgrounded() {
//App in background
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppForegrounded() {
// App in foreground
}
}
in app.gradle
dependencies {
...
implementation "android.arch.lifecycle:extensions:1.1.0"
//New Android X dependency is this -
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
}
allprojects {
repositories {
...
google()
jcenter()
maven { url 'https://maven.google.com' }
}
}
You can read more about Lifecycle related architecture components here - https://developer.android.com/topic/libraries/architecture/lifecycle
DO NOT USE THIS ANSWER
user1269737's answer is the proper (Google/Android approved) way to do this. Go read their answer and give them a +1.
I'll leave my original answer here for posterity's sake. This was the best available back in 2012, but now Android has proper support for this.
Original answer
The key is using ActivityLifecycleCallbacks
(note that this requires Android API level 14 (Android 4.0)). Just check if the number of stopped activities is equal to the number of started activities. If they're equal, your application is being backgrounded. If there are more started activities, your application is still visible. If there are more resumed than paused activities, your application is not only visible, but it's also in the foreground. There are 3 main states that your activity can be in, then: visible and in the foreground, visible but not in the foreground, and not visible and not in the foreground (i.e. in the background).
The really nice thing about this method is that it doesn't have the asynchronous issues getRunningTasks()
does, but you also don't have to modify every Activity
in your application to set/unset something in onResumed()
/onPaused()
. It's just a few lines of code that's self contained, and it works throughout your whole application. Plus, there are no funky permissions required either.
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 has asked some good questions about this method that I'd like to respond to in this answer for everyone:
onStop()
is not called in low memory situations; is that a problem here?
No. The docs for onStop()
say:
Note that this method may never be called, in low memory situations where the system does not have enough memory to keep your activity's process running after its onPause() method is called.
The key here is "keep your activity's process running..." If this low memory situation is ever reached, your process is actually killed (not just your activity). This means that this method of checking for backgrounded-ness is still valid because a) you can't check for backgrounding anyway if your process is killed, and b) if your process starts again (because a new activity is created), the member variables (whether static or not) for MyLifecycleHandler
will be reset to 0
.
Does this work for configuration changes?
By default, no. You have to explicitly set configChanges=orientation|screensize
(|
with anything else you want) in your manifest file and handle the configuration changes, or else your activity will be destroyed and recreated. If you do not set this, your activity's methods will be called in this order: onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume
. As you can see, there is no overlap (normally, two activities overlap very briefly when switching between the two, which is how this backgrounding-detection method works). In order to get around this, you must set configChanges
so that your activity is not destroyed. Fortunately, I've had to set configChanges
already in all of my projects because it was undesirable for my entire activity to get destroyed on screen rotate/resize, so I've never found this to be problematic. (thanks to dpimka for refreshing my memory on this and correcting me!)
One note:
When I've said "background" here in this answer, I've meant "your app is no longer visible." Android activities can be visible yet not in the foreground (for example, if there's a transparent notification overlay). That's why I've updated this answer to reflect that.
It's important to know that Android has a weird limbo moment when switching activities where nothing is in the foreground. For this reason, if you check if your application is in the foreground when switching between activities (in the same app), you'll be told you're not in the foreground (even though your app is still the active app and is visible).
You can check if your app is in the foreground in your Activity
's onPause()
method after super.onPause()
. Just remember the weird limbo state I just talked about.
You can check if your app is visible (i.e. if it's not in the background) in your Activity
's onStop()
method after super.onStop()
.