How to detect when an Android app goes to the background and come back to the foreground
Asked Answered
M

45

452

I am trying to write an app that does something specific when it is brought back to the foreground after some amount of time. Is there a way to detect when an app is sent to the background or brought to the foreground?

Montreal answered 10/12, 2010 at 23:22 Comment(3)
May be to add a use case to the question because it doesn't seem to be obvious, so it's not addressed in the answers given. The app may start another app (Gallery for example), which will still reside in the same stack and appear as one of the app's screens, and then press Home button. None of the methods relying on App lifecycle (or even memory management) are able to detect this. They would trigger background state right when external Activity appears, not when you press Home.Bailee
This is the answer you're looking for: https://mcmap.net/q/80321/-how-to-detect-when-an-android-app-goes-to-the-background-and-come-back-to-the-foregroundFletafletch
See Google Solution: #3667522Viviyan
E
112

The onPause() and onResume() methods are called when the application is brought to the background and into the foreground again. However, they are also called when the application is started for the first time and before it is killed. You can read more in Activity.

There isn't any direct approach to get the application status while in the background or foreground, but even I have faced this issue and found the solution with onWindowFocusChanged and onStop.

For more details check here Android: Solution to detect when an Android app goes to the background and come back to the foreground without getRunningTasks or getRunningAppProcesses.

Evolute answered 10/12, 2010 at 23:22 Comment(8)
However this approach causes false positives as others pointed out, because these methods are also called when transitioning between activities in the same app.Iceberg
It's worse than that. I tried it and sometimes the onResume is called while the phone is locked. If you see the definition of the onResume in the documentation, you will find: Keep in mind that onResume is not the best indicator that your activity is visible to the user; a system window such as the keyguard may be in front. Use onWindowFocusChanged(boolean) to know for certain that your activity is visible to the user (for example, to resume a game).developer.android.com/reference/android/app/…Depolarize
The solution posted in the link doesn't use onResume/onPause, instead a combination of onBackPressed, onStop, onStart and onWindowsFocusChanged. It did work for me, and I have a rather complex UI hierarchy (with drawers, dynamic viewpagers, etc.)Cockalorum
The onPause and onResume are Activity specific. Not Application. When an App is put on background and then resumed, it resumes the specific Activity it was in before going to background. This means that you would need to implement whatever you want done on resuming from background in all Activity of your Application. I believe the original question was looking for something like a "onResume" for Application and not Activity.Gelt
See d60402's answer for a solution that is a little more universal than the one in the linked blog. Vardan's solution relies on there being a single entry activity to the app and no way to return to that activity besides using back.Kaule
I can't believe a proper API is not offered for such a common need. Initially I thought onUserLeaveHint() would cut it, but you can't tell if the user is leaving the application or notDomash
the android api changes fast enough, you'd think they could just slip in this feature...Helse
What the hell anything you will answer. The question was app minimize and he gave the answer is for activity minimized. How can this will be accepted answer.?Brigand
C
231

2018: Android supports this natively through lifecycle components.

March 2018 UPDATE: There is now a better solution. See ProcessLifecycleOwner. You will need to use the new architecture components 1.1.0 (latest at this time) but it’s specifically designed to do this.

There’s a simple sample provided in this answer but I wrote a sample app and a blog post about it.

Ever since I wrote this back in 2014, different solutions arose. Some worked, some were thought to be working, but had flaws (including mine!) and we, as a community (Android) learned to live with the consequences and wrote workarounds for the special cases.

Never assume a single snippet of code is the solution you’re looking for, it’s unlikely the case; better yet, try to understand what it does and why it does it.

The MemoryBoss class was never actually used by me as written here, it was just a piece of pseudo code that happened to work.

Unless there’s valid reason for you not to use the new architecture components (and there are some, especially if you target super old apis), then go ahead and use them. They are far from perfect, but neither were ComponentCallbacks2.

UPDATE / NOTES (November 2015): People has been making two comments, first is that >= should be used instead of == because the documentation states that you shouldn't check for exact values. This is fine for most cases, but bear in mind that if you only care about doing something when the app went to the background, you will have to use == and also combine it with another solution (like Activity Lifecycle callbacks), or you may not get your desired effect. The example (and this happened to me) is that if you want to lock your app with a password screen when it goes to the background (like 1Password if you're familiar with it), you may accidentally lock your app if you run low on memory and are suddenly testing for >= TRIM_MEMORY, because Android will trigger a LOW MEMORY call and that's higher than yours. So be careful how/what you test.

Additionally, some people have asked about how to detect when you get back.

The simplest way I can think of is explained below, but since some people are unfamiliar with it, I'm adding some pseudo code right here. Assuming you have YourApplication and the MemoryBoss classes, in your class BaseActivity extends Activity (you will need to create one if you don't have one).

@Override
protected void onStart() {
    super.onStart();

    if (mApplication.wasInBackground()) {
        // HERE YOU CALL THE CODE YOU WANT TO HAPPEN ONLY ONCE WHEN YOUR APP WAS RESUMED FROM BACKGROUND
        mApplication.setWasInBackground(false);
    }
}

I recommend onStart because Dialogs can pause an activity so I bet you don't want your app to think "it went to the background" if all you did was display a full screen dialog, but your mileage may vary.

And that's all. The code in the if block will only be executed once, even if you go to another activity, the new one (that also extends BaseActivity) will report wasInBackground is false so it won't execute the code, until onMemoryTrimmed is called and the flag is set to true again.

UPDATE / NOTES (April 2015): Before you go all Copy and Paste on this code, note that I have found a couple of instances where it may not be 100% reliable and must be combined with other methods to achieve the best results. Notably, there are two known instances where the onTrimMemory call back is not guaranteed to be executed:

  1. If your phone locks the screen while your app is visible (say your device locks after nn minutes), this callback is not called (or not always) because the lockscreen is just on top, but your app is still "running" albeit covered.

  2. If your device is relatively low on memory (and under memory stress), the Operating System seems to ignore this call and go straight to more critical levels.

Now, depending how important it's for you to know when your app went to the background, you may or may not need to extend this solution together with keeping track of the activity lifecycle and whatnot.

Just keep the above in mind and have a good QA team ;)

END OF UPDATE

It may be late but there's a reliable method in Ice Cream Sandwich (API 14) and Above.

Turns out that when your app has no more visible UI, a callback is triggered. The callback, which you can implement in a custom class, is called ComponentCallbacks2 (yes, with a two). This callback is only available in API Level 14 (Ice Cream Sandwich) and above.

You basically get a call to the method:

public abstract void onTrimMemory (int level)

The Level is 20 or more specifically

public static final int TRIM_MEMORY_UI_HIDDEN

I've been testing this and it always works, because level 20 is just a "suggestion" that you might want to release some resources since your app is no longer visible.

To quote the official docs:

Level for onTrimMemory(int): the process had been showing a user interface, and is no longer doing so. Large allocations with the UI should be released at this point to allow memory to be better managed.

Of course, you should implement this to actually do what it says (purge memory that hasn't been used in certain time, clear some collections that have been sitting unused, etc. The possibilities are endless (see the official docs for other possible more critical levels).

But, the interesting thing, is that the OS is telling you: HEY, your app went to the background!

Which is exactly what you wanted to know in the first place.

How do you determine when you got back?

Well that's easy, I'm sure you have a "BaseActivity" so you can use your onResume() to flag the fact that you're back. Because the only time you will be saying you're not back is when you actually receive a call to the above onTrimMemory method.

It works. You don't get false positives. If an activity is resuming, you're back, 100% of the times. If the user goes to the back again, you get another onTrimMemory() call.

You need to suscribe your Activities (or better yet, a custom class).

The easiest way to guarantee that you always receive this is to create a simple class like this:

public class MemoryBoss 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) {
            // We're in the Background
        }
        // you might as well implement some memory cleanup here and be a nice Android dev.
    }
}

In order to use this, in your Application implementation (you have one, RIGHT?), do something like:

MemoryBoss mMemoryBoss;
@Override
public void onCreate() {
   super.onCreate();
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
      mMemoryBoss = new MemoryBoss();
      registerComponentCallbacks(mMemoryBoss);
   } 
}

If you create an Interface you could add an else to that if and implement ComponentCallbacks (without the 2) used in anything below API 14. That callback only has the onLowMemory() method and does not get called when you go to the background, but you should use it to trim memory.

Now launch your App and press home. Your onTrimMemory(final int level) method should be called (hint: add logging).

The last step is to unregister from the callback. Probably the best place is the onTerminate() method of your App, but, that method doesn't get called on a real device:

/**
 * This method is for use in emulated process environments.  It will
 * never be called on a production Android device, where processes are
 * removed by simply killing them; no user code (including this callback)
 * is executed when doing so.
 */

So unless you really have a situation where you no longer want to be registered, you can safety ignore it, since your process is dying at OS level anyway.

If you decide to unregister at some point (if you, for example, provide a shutdown mechanism for your app to clean up and die), you can do:

unregisterComponentCallbacks(mMemoryBoss);

And that's it.

Cockalorum answered 12/11, 2013 at 3:30 Comment(31)
When checking this from a service, seems to only fire when the home button is pressed. Pressing the back button doesn't fire this on KitKat.Maineetloire
The service has no UI so it could be related to that. Do the check in your base activity, not on a service. You want to know when your UI is hidden (and perhaps tell the service, so it goes Foreground)Cockalorum
It doesn't work when you turn off your phone. It is not triggered.Groschen
Well, the phone shutdown is a completely different broadcast, create a BroadcastReceiver that filters android.intent.action.ACTION_SHUTDOWNand you will get a different call. If the phone is shutting down, you shouldn't need to worry much… your process will die soon. ;)Cockalorum
I just found a SO question/answer that demonstrates the above and saves me the copy/paste from my code ;) #2190626Cockalorum
Using the ComponentCallbacks2.onTrimMemory() (in combination with ActivityLifecycleCallbacks) is the only reliable solution I found so far, thanks Martin! For those interested, see my provided answer.Hob
I've been using this method since a year ago and it's always been reliable to me. It's good to know other people use it too. I just use level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN which avoids the problem in your update, point 2. Regarding the point 1, it's not a concern to me, since the app didn't really go to the background, so that's the way it's supposed to work.Cowden
Good to know it works for you! Unfortunately, some apps do need to determine those conditions (mostly for security reasons) so #1 is a valid concern. And using >= in the condition means that your app will do X thing when you get a higher callback for low memory… which may not be desirable for most apps; again, it depends on the app's type. :) I have certainly used it in three apps so far, and it works, but in one in particular I had to deal with the above cases (1 and 2) hence why I decided to warn people about them.Cockalorum
As @Cowden mentions, if you carefully read the Android API documentation, it states 'You should never compare to exact values of the level, since new intermediate values may be added -- you will typically want to compare if the value is greater or equal to a level you are interested in.' developer.android.com/reference/android/content/… Therefore I'd recommend Martin Marconcini change the code to list "level > ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN"Ossicle
@Ossicle It's important to understand that using >= may not be the desired behavior. Imagine you need to LOCK your app (with a pwd screen for example) if it went to the background. With your code, the app will lock itself if there's a LOW MEMORY, clearly not what you wanted. As always, test regularly and make sure that you're getting the intended behavior. Each case is different, maybe one day Android will be less stupid and literally have a decent lifecycle one can depend upon ;)Cockalorum
By Application implementation you just mean a class that extends Application right? Thanks so much for the detailed answerBoysenberry
Also, what method should I use to check if the user came back? The TRIM_MEMORY_UI_HIDDEN is only for leaving the app. Thanks so muchBoysenberry
@Rich yes. The "came back" part is explained in the post, you'd basically need to track it in a BaseActivity class onResume() method, if an onResume is fired, you're back.Cockalorum
I tried that but on resume and getting fired whenever I switch between activities that extend the base activity. What should I do? ThanksBoysenberry
@Rich I don't see your problem,onResume() is just to know that you're back, do something and then leave a flag that you don't have to do it again until you go to the background again. So yes, the check will be made on every onResume, but that's fine, you only have to execute the code once. Post a specific question with your code if you need more information :) Good luck!Cockalorum
@MartínMarconcini Thank you so much for your response. I am not quite sure on how to use flags, as I have never used them before. I have looked online, but there aren't many resources about them online. What should I do, could you maybe provide an example? ThanksBoysenberry
@Rich I have added some more information at the beginning, re-read all the post again. Hope that helps you. Remember that a flag is just a predefined bit or bit sequence that holds a binary value. Typically, a program uses a flag to remember something or to leave a sign for another program. (copy paste from the definition found on Google). Your flag here, is the mApplication.wasInBackground bit. ;)Cockalorum
@MartínMarconcini Thanks so much for the edit on your post! I have a really stupid question...Is mApplication the BaseActivity? Also, when I try to use a flag by doing BaseActivity.wasInBackground I get an error saying cannot resolve method wasInBackground. So do I need to declare the flag somewhere or something? Sorry if this is a very basic question. Thanks so much for everything, you have helped me a lot. Please let me know. :)Boysenberry
@Rich mApplication is an instance of YourApplication extends ApplicationCockalorum
So I am still getting the resolve method error. Would you like to move this conversation to chat? Thanks so much, I am learning a lot from you!Boysenberry
Let us continue this discussion in chat.Boysenberry
@MartínMarconcini Could you please elaborate what you have done for the point which you mentioned? "Now, depending how important it's for you to know when your app went to the background, you may or may not need to extend this solution together with keeping track of the activity lifecycle and whatnot."Graniteware
Continuation of above comment: I combined your solution with @d60402 's solution. But, there are 2 use-cases in which it does not work: App is in foreground and 1. Device has lock screen enabled (pattern). If I press on power button and immediately, I press power button and unlock. 2. Device does not have lock screen enabled. I press power button. Screen display is turned off. Press power button again to unlock. Any help is appreciated. I tried 1Password and the above use-cases work.Graniteware
Hi @Graniteware I don't remember right now what we've done (tho unlike 1pwd our requirements at the time were softer so I wouldn't be surprised if we didn't account for that case). Subscribing to Activity Lifecycle + This + @d60402's solution is perhaps what you need. When you press the power button your activity will be paused (afaicr), you could also detect when the powerbutton is pressed (KeyEvent.KEYCODE_POWER if I am not mistaken) and react there. Unfortunately, due to Android's design, there's no one-stop-shop solution to this (simple?) problem.Cockalorum
I do remember (and I think i mention it in one of the updates, the lock screen doesn't count as "UI Hidden"). I'd explore the solution of detecting the power button and making that higher priority to decide when to lock, regardless of the other events.Cockalorum
Thanks @MartínMarconcini But, it does not seem possible to capture power button press as mentioned in the comments of https://mcmap.net/q/81526/-how-to-hook-into-the-power-button-in-android. I went with alternate approach of finding out if screen is off for this scenario: https://mcmap.net/q/81527/-android-listen-for-power-key-pressGraniteware
Good finding @GranitewareCockalorum
For FragmentActivity you also might want to add` level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE` tooRhinencephalon
This is not reliable 100% of the times. I've had (non-reproducable) occasions where onTrimMemory is not called.Mastaba
@Mastaba the reasons (and possible solutions) have been covered in the 2015 Update of the answer. tl;dr: onTrimMemory is not 100% reliable but acceptable for most use cases. If you need further security, you need to use combined solutions.Cockalorum
the only thing I don't like about this answer is that I cannot double upvoted, this should be the accepted answer!Transship
S
178

Here's how I've managed to solve this. It works on the premise that using a time reference between activity transitions will most likely provide adequate evidence that an app has been "backgrounded" or not.

First, I've used an android.app.Application instance (let's call it MyApplication) which has a Timer, a TimerTask, a constant to represent the maximum number of milliseconds that the transition from one activity to another could reasonably take (I went with a value of 2s), and a boolean to indicate whether or not the app was "in the background":

public class MyApplication extends Application {

    private Timer mActivityTransitionTimer;
    private TimerTask mActivityTransitionTimerTask;
    public boolean wasInBackground;
    private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000;
    ...

The application also provides two methods for starting and stopping the timer/task:

public void startActivityTransitionTimer() {
    this.mActivityTransitionTimer = new Timer();
    this.mActivityTransitionTimerTask = new TimerTask() {
        public void run() {
            MyApplication.this.wasInBackground = true;
        }
    };

    this.mActivityTransitionTimer.schedule(mActivityTransitionTimerTask,
                                           MAX_ACTIVITY_TRANSITION_TIME_MS);
}

public void stopActivityTransitionTimer() {
    if (this.mActivityTransitionTimerTask != null) {
        this.mActivityTransitionTimerTask.cancel();
    }

    if (this.mActivityTransitionTimer != null) {
        this.mActivityTransitionTimer.cancel();
    }

    this.wasInBackground = false;
}

The last piece of this solution is to add a call to each of these methods from the onResume() and onPause() events of all activities or, preferably, in a base Activity from which all of your concrete Activities inherit:

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

    MyApplication myApp = (MyApplication)this.getApplication();
    if (myApp.wasInBackground)
    {
        //Do specific came-here-from-background code
    }

    myApp.stopActivityTransitionTimer();
}

@Override
public void onPause()
{
    super.onPause();
    ((MyApplication)this.getApplication()).startActivityTransitionTimer();
}

So in the case when the user is simply navigating between the activities of your app, the onPause() of the departing activity starts the timer, but almost immediately the new activity being entered cancels the timer before it can reach the max transition time. And so wasInBackground would be false.

On the other hand when an Activity comes to the foreground from the Launcher, device wake up, end phone call, etc., more than likely the timer task executed prior to this event, and thus wasInBackground was set to true.

Soidisant answered 22/3, 2013 at 14:42 Comment(15)
Hi d60402, your answer is really helpful.. thank you so much for this reply... small notice.. MyApplication should mention in Manifest file application tag like android:name="MyApplication", otherwise app crashes... just to help somebody like meOsculum
mark of the great programmer, simple solution to one of the most complicated problem I ever came accross.Thromboplastin
Awesome solution ! Thanks. If anyone gets "ClassCastException" error then you might have missed adding it in the application tag inside your Manifest.xml <application android:name="your.package.MyApplication"Percuss
This is a nice and simple implementation. However I believe this should be implemented in onStart/onStop rather than onPause/onResume. The onPause will be called even if I start a dialog which partially covers the activity. And closing the dialog would actually call onResume make it appear as if the app has just come to foregroundFoal
I'm hoping to use a variation of this solution. The point about dialogues identified above is a problem for me, so I tried @Shubhayu's suggestion (onStart/onStop). The doesn't help however because when going A->B, Activity B's onStart() is called before Activity A's onStop().Marry
works for me, thanks a lot for sharing your solution. I'm curious if certain apps need a higher MAX_ACTIVITY_TRANSITION_TIME_MS threshold when doing intensive processing in-between activitiesLiddell
good solution. the only problem is when coming back lock screen wasInBackground becomes true. Any way to avoid it ?Reverent
please note that you can't use (onStart/onStop) with this solution instead of (onPause/onResume) #17214952Draper
Good solution to a silly problem. It should be noted that if you have any activities from 3rd parties in your app, this solution won't work when those are started (because you can't alter the onPause/onResume methods).Lyrate
@Reverent has it right. There is no guarantee onStop() of the parent activity is called before onStart() of the new activity.Siege
Good solution to be combined with MartínMarconcini 's solution. Because if app is put to background and launched again within the time interval (2seconds), we will fail to detect app coming to foreground. So, it should be combined with Martin's solution depending on how critical it is to find app coming to foreground. Also, in Android M onwards, whenever we prompt for permission, this solution gives false positive. Have to tweak this solution a bit for permission request use-case. Has anyone already tweaked it successfully? @d60402, have you covered this use-case later on?Graniteware
Funny thing: if you are using Kotlin, there is no way to call .schedule() method of timer. It just won't accept any of params (both Long and Date)Albertalberta
Fantastic! The same solution can also work if you have a Base Activity class which inherits from Activity instead of Application. Just change the "MyApplication myApp = (MyApplication)this.getApplication();" to "Application myApp = this.getApplication();" and similar.Arlon
You, sir, are a GOD. Needed to detect a Xamarin.Android app background/foreground workflow, and using a standard C# Timer, a BaseActivity and a BaseApplication, this has been the cleanest, easiest solution I found so far.Flange
Great answer. But instead of overriding lifecycle in the Activity, you can do this in the Application itself. https://mcmap.net/q/80321/-how-to-detect-when-an-android-app-goes-to-the-background-and-come-back-to-the-foregroundZellner
W
176

UPDATE November 2021

Actual setup is as follows

class App : Application() {
    override fun onCreate() {
        super.onCreate()
        ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleListener())
    }
}

class AppLifecycleListener : DefaultLifecycleObserver {

    override fun onStart(owner: LifecycleOwner) { // app moved to foreground
    }

    override fun onStop(owner: LifecycleOwner) { // app moved to background
    }
}

Dependencies

implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common:$lifecycle_version"

ORIGINAL ANSWER

ProcessLifecycleOwner seems to be a promising solution also.

ProcessLifecycleOwner will dispatch ON_START, ON_RESUME events, as a first activity moves through these events. ON_PAUSE, ON_STOP, events will be dispatched with a delay after a last activity passed through them. This delay is long enough to guarantee that ProcessLifecycleOwner won't send any events if activities are destroyed and recreated due to a configuration change.

An implementation can be as simple as

class AppLifecycleListener : LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onMoveToForeground() { // app moved to foreground
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onMoveToBackground() { // app moved to background
    }
}

// register observer
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleListener())

According to source code, current delay value is 700ms.

Also using this feature requires the dependencies:

implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"
Welladvised answered 9/6, 2017 at 15:29 Comment(15)
Note that you need to add the lifecycle dependencies implementation "android.arch.lifecycle:extensions:1.0.0" and annotationProcessor "android.arch.lifecycle:compiler:1.0.0" from Google's repository (i.e google())Rhodia
This worked great for me, thank you. I had to use api 'android.arch.lifecycle:extensions:1.1.0' instead of implementation due to error stating Android dependency has different version for the compile and runtime classpath.Libna
This is a great solution because it works in modules without needing an Activity reference!Fount
This is not working when app is crashed. Is there any solution to get app crashed event also through this solutionUmberto
@SirCodesalot not required for the 2.2.0 version.Ac
@tejraj, well, I think, if an application has crashed, it cannot continue working and react to any event (so will won't do any useful job).Featherbrain
I just tried and checked it with a debugger, it calls both these methods twice continuously.Aldred
Just a FYI, the annotation @OnLifeCycleEvent is deprecated.Leatherback
@OnLifecycleEvent is deprecated. developer.android.com/jetpack/androidx/releases/…Zarger
How do I integrate this into my application? I have no idea. All I have in my app is activities and a service. I have tried instantiating it in my primary activity but the onCreate is never called. All I want to do is put the BtScanner in a low duty cycle when in background and a medium duty cycle when in the foreground (visible on screen).Speroni
This doesn't work as expected when an external activity is called, like a File Picker, in that case the app will be notified as background when the Picker is opened and the foreground again when the Picker is closed. Any way around that?Eisegesis
@Eisegesis you could also use onResume for this. Does not make any difference, but you also get a callback invoked in such cases as external activity or dialog.Quintain
Notice that onStop() is also called when lock screen is activated, which may not be the behaviour that is wanted.Discolor
Yeah, lifecycle-extensions is pretty terrible. STILL doesn't work if you open an in-app browser, for example, which called pause and stop on app.Guereza
It's 2023 and there's STILL NOT A SOLUTION to detecting if an app is opened from the background.Guereza
A
171

Edit: the new architecture components brought something promising: ProcessLifecycleOwner, see @vokilam's answer


The actual solution according to a Google I/O talk:

class YourApplication : Application() {

  override fun onCreate() {
    super.onCreate()
    registerActivityLifecycleCallbacks(AppLifecycleTracker())
  }

}


class AppLifecycleTracker : Application.ActivityLifecycleCallbacks  {

  private var numStarted = 0

  override fun onActivityStarted(activity: Activity?) {
    if (numStarted == 0) {
      // app went to foreground
    }
    numStarted++
  }

  override fun onActivityStopped(activity: Activity?) {
    numStarted--
    if (numStarted == 0) {
      // app went to background
    }
  }

}

Yes. I know it's hard to believe this simple solution works since we have so many weird solutions here.

But there is hope.

Anhydride answered 8/3, 2017 at 18:31 Comment(22)
Please change extends to implements.Trilateration
This works perfectly! I already tried so many weird solutions that had so many flaws... very thanks! I've been looking for this for a while.Stylet
Maybe I am wrong, but this is correct as long as you're able to register the callback at the very beginning of the app. If not, you are going to miss the first 'activityStarted' which will mess up the activity counter leading to unpredictable stateVane
It works for multiple activities, but for one - onrotate will indicate about all activities are gone or in backgroundStationmaster
@Vane you are correct, but that's part of this solution so need to worry. If firebase relies on this, I think my mediocre app can too :) Great answer BTW.Related
@Stationmaster Check the link to I/O provided in the top of the answer. You can check time gaps between activity stop and start to determine if you really went to background or not. This is a brilliant solution, actually.Barony
@ThiagoPorciúncula The solution is really good but I have a problem, if my app is opened and I lock the screen with power button, the app is moved to background or killed and I have to open again when I unlock the screen, If I remove the callback and locks the screen, when the screen is unlocked the app is there.Penang
A beautiful solution. Works better than anything else I've tried.Epicontinental
In onActivityStarted, you can "activity.getIntent().putExtra()", which you can then read it in your Activity onResume. Check hasExtra() and you know you've come in from the background. Works great.Cohlette
Is there a Java solution? This is kotlin.Barayon
How to detect if the app is gonna be unloaded complitly?Oppress
one of the best stackoverflow answers so far, someone has to make this accepted answerCisneros
You should use an AtomicInteger instead of an int, It is safer than int to avoid calling multiple times the foreground callback.Crabbed
@Crabbed This is registered at the application level, I don't see how different threads would be executing that at the same time. Besides, I'm merely reproducing the code from the video, and there's no AtomicInteger there.Fletafletch
@ThiagoPorciúncula Actually, yes, this code will work "as if" if the implementation is short, simple and explicit. But some problems can occurs if the developer is starting a new thread at the beginning of onActivityStarted and doing a long work inside the foreground brackets. In this case, the foreground brackets can be called twice and more. AtomicInteger is generally used to handle this cases, furthermore, AtomicInteger expose a method to Increment and get the value in only 1 instruction :)Crabbed
@Thiago Porciúncula is this implementation work fine in the old devices or is there any kind of concerns(from API level 14).Laing
@Laing I’m not sure, test it out and let us know! :)Fletafletch
@tainy yes, the methods are callbacks for when individual activities are started and stopped. That’s why there’s a counter.Fletafletch
@ThiagoPorciúncula got it, my fault!Westerfield
@Stationmaster To work around the problem with configuration changes (including rotation) when you have only 1 activity currently counted, use "isChangingConfigurations" flag from the activity to guard the increment/decrement and you will have a fully working solution to this problem.Barthold
@OnLifecycleEvent is deprecated. developer.android.com/jetpack/androidx/releases/…Zarger
Is there a way to include external activities such as a file picker launched via android.intent.action.PICK? I would like to know when the entire app goes to the background, not just the custom activities.Buroker
E
112

The onPause() and onResume() methods are called when the application is brought to the background and into the foreground again. However, they are also called when the application is started for the first time and before it is killed. You can read more in Activity.

There isn't any direct approach to get the application status while in the background or foreground, but even I have faced this issue and found the solution with onWindowFocusChanged and onStop.

For more details check here Android: Solution to detect when an Android app goes to the background and come back to the foreground without getRunningTasks or getRunningAppProcesses.

Evolute answered 10/12, 2010 at 23:22 Comment(8)
However this approach causes false positives as others pointed out, because these methods are also called when transitioning between activities in the same app.Iceberg
It's worse than that. I tried it and sometimes the onResume is called while the phone is locked. If you see the definition of the onResume in the documentation, you will find: Keep in mind that onResume is not the best indicator that your activity is visible to the user; a system window such as the keyguard may be in front. Use onWindowFocusChanged(boolean) to know for certain that your activity is visible to the user (for example, to resume a game).developer.android.com/reference/android/app/…Depolarize
The solution posted in the link doesn't use onResume/onPause, instead a combination of onBackPressed, onStop, onStart and onWindowsFocusChanged. It did work for me, and I have a rather complex UI hierarchy (with drawers, dynamic viewpagers, etc.)Cockalorum
The onPause and onResume are Activity specific. Not Application. When an App is put on background and then resumed, it resumes the specific Activity it was in before going to background. This means that you would need to implement whatever you want done on resuming from background in all Activity of your Application. I believe the original question was looking for something like a "onResume" for Application and not Activity.Gelt
See d60402's answer for a solution that is a little more universal than the one in the linked blog. Vardan's solution relies on there being a single entry activity to the app and no way to return to that activity besides using back.Kaule
I can't believe a proper API is not offered for such a common need. Initially I thought onUserLeaveHint() would cut it, but you can't tell if the user is leaving the application or notDomash
the android api changes fast enough, you'd think they could just slip in this feature...Helse
What the hell anything you will answer. The question was app minimize and he gave the answer is for activity minimized. How can this will be accepted answer.?Brigand
H
80

Based on Martín Marconcinis answer (thanks!) I finally found a reliable (and very simple) solution.

public class ApplicationLifecycleHandler implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {

    private static final String TAG = ApplicationLifecycleHandler.class.getSimpleName();
    private static boolean isInBackground = false;

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

    @Override
    public void onActivityStarted(Activity activity) {
    }

    @Override
    public void onActivityResumed(Activity activity) {

        if(isInBackground){
            Log.d(TAG, "app went to foreground");
            isInBackground = false;
        }
    }

    @Override
    public void onActivityPaused(Activity activity) {
    }

    @Override
    public void onActivityStopped(Activity activity) {
    }

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

    @Override
    public void onActivityDestroyed(Activity activity) {
    }

    @Override
    public void onConfigurationChanged(Configuration configuration) {
    }

    @Override
    public void onLowMemory() {
    }

    @Override
    public void onTrimMemory(int i) {
        if(i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN){
            Log.d(TAG, "app went to background");
            isInBackground = true;
        }
    }
}

Then add this to your onCreate() of your Application class

public class MyApp extends android.app.Application {

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

        ApplicationLifeCycleHandler handler = new ApplicationLifeCycleHandler();
        registerActivityLifecycleCallbacks(handler);
        registerComponentCallbacks(handler);

    }

}
Hob answered 2/6, 2015 at 13:53 Comment(9)
Can yo show how you use this in an app, do I call this from App class or somewhere else?Ceramics
this is perfect thank you!! works great in testing so farFaustina
This example if incomplete. What is registerActivityLifecycleCallbacks?Hawkweed
its a method in class android.app.ApplicationHob
well done +1 to go on top, because it is perfect, don't look other answers, this is based on @reno answer but with real exampleTweed
Have tried your answer but is not as reliable. the onTrimMemory callback will not get triggered when the screen is locked nor when pressing the "power" button to lock the screen. It won't also always return TRIM_MEMORY_UI_HIDDEN if your app is visible and you open another app via a status bar notification. The only reliable solution is to implement the ActivityLifecycleCallbacks and adjust it to ones use case.Latticed
does not distinguish between close las activity by backbutton (really close) and put in background (by home button)Wandawander
Why have you made isInBackground static?Wrathful
Do I have this add that in my onCreate of every single activity?Autodidact
S
64

We use this method. It looks too simple to work, but it was well-tested in our app and in fact works surprisingly well in all cases, including going to home screen by "home" button, by "return" button, or after screen lock. Give it a try.

Idea is, when in foreground, Android always starts new activity just before stopping previous one. That's not guaranteed, but that's how it works. BTW, Flurry seems to use the same logic (just a guess, I didn't check that, but it hooks at the same events).

public abstract class BaseActivity extends Activity {

    private static int sessionDepth = 0;

    @Override
    protected void onStart() {
        super.onStart();       
        sessionDepth++;
        if(sessionDepth == 1){
        //app came to foreground;
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (sessionDepth > 0)
            sessionDepth--;
        if (sessionDepth == 0) {
            // app went to background
        }
    }

}

Edit: as per comments, we also moved to onStart() in later versions of the code. Also, I'm adding super calls, which were missing from my initial post, because this was more of a concept than a working code.

Shangrila answered 30/8, 2014 at 13:2 Comment(9)
This is the most reliable answer, although I use onStart instead of onResume.Cockade
You should add calls to super.onResume() and super.onStop() in the overriden methods. Otherwise an android.app.SuperNotCalledException is thrown.Metchnikoff
for me it doesn't work... or at least it fire the event when you are rotating the device too (which is kind of a false positive imho).Sycee
Very simple and effective solution! But I'm not sure it works with partially transparent activities that let some parts of the previous activity visible. From the docs, onStop is called when the activity is no longer visible to the user.Bookrest
what happens if the user changes the orientation on the first activity? It will report that the app went to background which isn't true. How do you handle this scenario?Xanthene
In order to avoid reporting that the app went to background when rotating the device, all I had to do was add android:configChanges="orientation|screenSize" to the AndroidManifest for every activity that is allowed to rotate.Pheidippides
@LuccasCorrea that's not a valid way to handle this. Every activity that you add that manifest entry for will then have to implement it's own onConfigurationChanged method. From the docs: developer.android.com/guide/topics/manifest/… A better approach would be to post a delayed runnable (only a few milliseconds) that would decrement sessionDepth inside onStopWilkins
Worked for me, really straight forwardZucker
@Wilkins can you please add the code for your last explanation of the post delayed runnable?Sinatra
E
55

If your app consists of multiple activites and/or stacked activites like a tab bar widget, then overriding onPause() and onResume() will not work. I.e when starting a new activity the current activites will get paused before the new one is created. The same applies when finishing (using "back" button) an activity.

I've found two methods that seem to work as wanted.

The first one requires the GET_TASKS permission and consists of a simple method that checks if the top running activity on the device belongs to application, by comparing package names:

private boolean isApplicationBroughtToBackground() {
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> tasks = am.getRunningTasks(1);
    if (!tasks.isEmpty()) {
        ComponentName topActivity = tasks.get(0).topActivity;
        if (!topActivity.getPackageName().equals(context.getPackageName())) {
            return true;
        }
    }

    return false;
}

This method was found in the Droid-Fu (now called Ignition) framework.

The second method that I've implemented my self does not require the GET_TASKS permission, which is good. Instead it is a little more complicated to implement.

In you MainApplication class you have a variable that tracks number of running activities in your application. In onResume() for each activity you increase the variable and in onPause() you decrease it.

When the number of running activities reaches 0, the application is put into background IF the following conditions are true:

  • The activity being paused is not being finished ("back" button was used). This can be done by using method activity.isFinishing()
  • A new activity (same package name) is not being started. You can override the startActivity() method to set a variable that indicates this and then reset it in onPostResume(), which is the last method to be run when an activity is created/resumed.

When you can detect that the application has resigned to the background it is easy detect when it is brought back to foreground as well.

Emetine answered 26/3, 2012 at 17:19 Comment(6)
Google will probably reject an app that uses ActivityManager.getRunningTasks(). The documentation states that it is foe dev purposes only. developer.android.com/reference/android/app/…Unstriped
Just want to mention this question because there are issues with getRunnintTasks()Groom
I found I had to use a combination of these approaches. onUserLeaveHint() was called when launching an activity in 14. ` @Override public void onUserLeaveHint() { inBackground = isApplicationBroughtToBackground(); } `Tjirebon
Users won't be too happy about using a powerful permission android.permission.GET_TASKS.Dumpling
is that possible to know activity is come from background ?Manducate
getRunningTasks is deprecated in API level 21.Sycee
D
37

Create a class that extends Application. Then in it we can use its override method, onTrimMemory().

To detect if the application went to the background, we will use:

 @Override
    public void onTrimMemory(final int level) {
        if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // Works for Activity
            // Get called every-time when application went to background.
        } 
        else if (level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { // Works for FragmentActivty
        }
    }
Donatist answered 3/8, 2015 at 7:42 Comment(2)
For FragmentActivity you also might want to add level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE too.Rhinencephalon
Thanks lot for pointing to this method, i need to show a Pin Dialog whenever user resume the activity for background, used this method to write a pref value and checked this value on baseActivity.Slushy
A
19

Consider using onUserLeaveHint. This will only be called when your app goes into the background. onPause will have corner cases to handle, since it can be called for other reasons; for example if the user opens another activity in your app such as your settings page, your main activity's onPause method will be called even though they are still in your app; tracking what is going in will lead to bugs when you can instead simply use the onUserLeaveHint callback which does what you are asking.

When on UserLeaveHint is called, you can set a boolean inBackground flag to true. When onResume is called, only assume you came back into the foreground if the inBackground flag is set. This is because onResume will also be called on your main activity if the user was just in your settings menu and never left the app.

Remember that if the user hits the home button while in your settings screen, onUserLeaveHint will be called in your settings activity, and when they return onResume will be called in your settings activity. If you only have this detection code in your main activity you will miss this use case. To have this code in all your activities without duplicating code, have an abstract activity class which extends Activity, and put your common code in it. Then each activity you have can extend this abstract activity.

For example:

public abstract AbstractActivity extends Activity {
    private static boolean inBackground = false;

    @Override
    public void onResume() {
        if (inBackground) {
            // You just came from the background
            inBackground = false;
        }
        else {
            // You just returned from another activity within your own app
        }
    }

    @Override
    public void onUserLeaveHint() {
        inBackground = true;
    }
}

public abstract MainActivity extends AbstractActivity {
    ...
}

public abstract SettingsActivity extends AbstractActivity {
    ...
}
Anuska answered 20/9, 2012 at 23:23 Comment(4)
onUserLeaveHint is also called when navigating to another activityMelissiamelita
onUserLeaveHint isn't called when e.g. a phone call comes in and the calling activity becomes active, so this has an edge case as well - there could be other cases too, since you can add a flag to the intent to suppress the onUserLeaveHint call. developer.android.com/reference/android/content/…Isobath
Also, onResume doesn't work well. I tried it and sometimes the onResume is called while the phone is locked. If you see the definition of the onResume in the documentation, you will find: Keep in mind that onResume is not the best indicator that your activity is visible to the user; a system window such as the keyguard may be in front. Use onWindowFocusChanged(boolean) to know for certain that your activity is visible to the user (for example, to resume a game).developer.android.com/reference/android/app/…Depolarize
this solution does not help to decide foreground/background if there are multiple activities.Plz refer #3667522Merchant
D
17

The android.arch.lifecycle package provides classes and interfaces that let you build lifecycle-aware components

Your application should implement the LifecycleObserver interface:

public class MyApplication extends Application implements LifecycleObserver {

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

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    private void onAppBackgrounded() {
        Log.d("MyApp", "App in background");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    private void onAppForegrounded() {
        Log.d("MyApp", "App in foreground");
    }
}

To do that, you need to add this dependency to your build.gradle file:

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

As recommended by Google, you should minimize the code executed in the lifecycle methods of activities:

A common pattern is to implement the actions of the dependent components in the lifecycle methods of activities and fragments. However, this pattern leads to a poor organization of the code and to the proliferation of errors. By using lifecycle-aware components, you can move the code of dependent components out of the lifecycle methods and into the components themselves.

You can read more here: https://developer.android.com/topic/libraries/architecture/lifecycle

Detinue answered 23/11, 2018 at 8:36 Comment(2)
and add this to manifest like: <application android:name=".AnotherApp">Trioecious
@OnLifecycleEvent is deprecated. developer.android.com/jetpack/androidx/releases/…Zarger
G
14

ActivityLifecycleCallbacks might be of interest, but it isn't well documented.

Though, if you call registerActivityLifecycleCallbacks() you should be able to get callbacks for when Activities are created, destroyed, etc. You can call getComponentName() for the Activity.

Guru answered 7/11, 2011 at 9:12 Comment(2)
Looks like this one is clean and works for me. ThanksComa
How is this different from the accepted answer, both rely on the same activity lifecycle right?Homologate
B
9

In your Application add the callback and check for root activity in a way like this:

@Override
public void onCreate() {
    super.onCreate();
    registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
        @Override
        public void onActivityStopped(Activity activity) {
        }

        @Override
        public void onActivityStarted(Activity activity) {
        }

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

        @Override
        public void onActivityResumed(Activity activity) {
        }

        @Override
        public void onActivityPaused(Activity activity) {
        }

        @Override
        public void onActivityDestroyed(Activity activity) {
        }

        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            if (activity.isTaskRoot() && !(activity instanceof YourSplashScreenActivity)) {
                Log.e(YourApp.TAG, "Reload defaults on restoring from background.");
                loadDefaults();
            }
        }
    });
}
Broucek answered 10/9, 2013 at 21:23 Comment(1)
I would consider using this manner of implementation. A transition from one activity to another just take a few milliseconds. Based on the time when the last activity disappears can be considered to re-login the user by a specific strategy.Vermiculation
E
7

You can use the ProcessLifecycleOwner attaching a lifecycle observer to it.

  public class ForegroundLifecycleObserver implements LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    public void onAppCreated() {
        Timber.d("onAppCreated() called");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onAppStarted() {
        Timber.d("onAppStarted() called");
    }

    @OnLifecycleEvent(Event.ON_RESUME)
    public void onAppResumed() {
        Timber.d("onAppResumed() called");
    }

    @OnLifecycleEvent(Event.ON_PAUSE)
    public void onAppPaused() {
        Timber.d("onAppPaused() called");
    }

    @OnLifecycleEvent(Event.ON_STOP)
    public void onAppStopped() {
        Timber.d("onAppStopped() called");
    }
}

then on the onCreate() of your Application class you call this:

ProcessLifecycleOwner.get().getLifecycle().addObserver(new ForegroundLifecycleObserver());

with this you will be able to capture the events of ON_PAUSE and ON_STOP of your application that happen when it goes in background.

Evesham answered 31/7, 2019 at 9:51 Comment(0)
P
6

I have created a project on Github app-foreground-background-listen

Create a BaseActivity for all Activity in your application.

public class BaseActivity extends Activity {

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    }

    public static boolean isAppInFg = false;
    public static boolean isScrInFg = false;
    public static boolean isChangeScrFg = false;

    @Override
    protected void onStart() {
        if (!isAppInFg) {
            isAppInFg = true;
            isChangeScrFg = false;
            onAppStart();
        }
        else {
            isChangeScrFg = true;
        }
        isScrInFg = true;

        super.onStart();
    }

    @Override
    protected void onStop() {
        super.onStop();

        if (!isScrInFg || !isChangeScrFg) {
            isAppInFg = false;
            onAppPause();
        }
        isScrInFg = false;
    }

    public void onAppStart() {

        // Remove this toast
        Toast.makeText(getApplicationContext(), "App in foreground",    Toast.LENGTH_LONG).show();

        // Your code
    }

    public void onAppPause() {

        // Remove this toast
        Toast.makeText(getApplicationContext(), "App in background",  Toast.LENGTH_LONG).show();

        // Your code
    }
}

Now use this BaseActivity as a super class of all your Activity like MainActivity extends BaseActivity and onAppStart will be called when you start your application and onAppPause() will be called when the application goes the background from any screen.

Phalan answered 6/8, 2015 at 10:5 Comment(2)
@kiran boghra: Are there any false positives in your solution?Poulenc
Perfect answer the onStart() and onStop() function can be use in this case. which tells you about your appBrahman
L
6

This is pretty easy with ProcessLifecycleOwner

Add these dependencies

implementation "android.arch.lifecycle:extensions:$project.archLifecycleVersion"
kapt "android.arch.lifecycle:compiler:$project.archLifecycleVersion"

In Kotlin:

class ForegroundBackgroundListener : LifecycleObserver {


    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun startSomething() {
        Log.v("ProcessLog", "APP IS ON FOREGROUND")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun stopSomething() {
        Log.v("ProcessLog", "APP IS IN BACKGROUND")
    }
}

Then in your base activity:

override fun onCreate() {
        super.onCreate()

        ProcessLifecycleOwner.get()
                .lifecycle
                .addObserver(
                        ForegroundBackgroundListener()
                                .also { appObserver = it })
    }

See my article on this topic: https://medium.com/@egek92/how-to-actually-detect-foreground-background-changes-in-your-android-application-without-wanting-9719cc822c48

Larisalarissa answered 3/1, 2018 at 12:45 Comment(1)
@OnLifecycleEvent is deprecated. developer.android.com/jetpack/androidx/releases/…Zarger
K
6

There are no straightforward lifecycle methods to tell you when the whole Application goes background/foreground.

I have done this with simple way. Follow the below instructions to detect application background/foreground phase.

With a little workaround, it is possible. Here, ActivityLifecycleCallbacks comes to the rescue. Let me walk through step-by-step.

  1. First, create a class that extends the android.app.Application and implements the ActivityLifecycleCallbacks interface. In the Application.onCreate(), register the callback.

    public class App extends Application implements 
        Application.ActivityLifecycleCallbacks {
    
        @Override
        public void onCreate() {
            super.onCreate();
            registerActivityLifecycleCallbacks(this);
        }
    }
    
  2. Register the “App” class in the Manifest as below, <application android:name=".App".

  3. There will be at least one Activity in the started state when the app is in the foreground and there will be no Activity in the started state when the app is in the background.

    Declare 2 variables as below in the “App” class.

    private int activityReferences = 0;
    private boolean isActivityChangingConfigurations = false;
    

    activityReferences will keep the count of number of activities in the started state. isActivityChangingConfigurations is a flag to indicate if the current Activity is going through configuration change like an orientation switch.

  4. Using the following code you can detect if the App comes foreground.

    @Override
    public void onActivityStarted(Activity activity) {
        if (++activityReferences == 1 && !isActivityChangingConfigurations) {
            // App enters foreground
        }
    }
    
  5. This is how to detect if the App goes background.

    @Override
    public void onActivityStopped(Activity activity) {
        isActivityChangingConfigurations = activity.isChangingConfigurations();
        if (--activityReferences == 0 && !isActivityChangingConfigurations) {
            // App enters background
        }
    }
    

How it works:

This is a little trick done with the way the Lifecycle methods are called in sequence. Let me walkthrough a scenario.

Assume that the user launches the App and the Launcher Activity A is launched. The Lifecycle calls will be,

A.onCreate()

A.onStart() (++activityReferences == 1) (App enters Foreground)

A.onResume()

Now Activity A starts Activity B.

A.onPause()

B.onCreate()

B.onStart() (++activityReferences == 2)

B.onResume()

A.onStop() (--activityReferences == 1)

Then the user navigates back from Activity B,

B.onPause()

A.onStart() (++activityReferences == 2)

A.onResume()

B.onStop() (--activityReferences == 1)

B.onDestroy()

Then the user presses Home button,

A.onPause()

A.onStop() (--activityReferences == 0) (App enters Background)

In case, if the user presses Home button from Activity B instead of Back button, still it will be the same and activityReferences will be 0. Hence, we can detect as the App entering Background.

So, what’s the role of isActivityChangingConfigurations? In the above scenario, suppose the Activity B changes the orientation. The callback sequence will be,

B.onPause()

B.onStop() (--activityReferences == 0) (App enters Background??)

B.onDestroy()

B.onCreate()

B.onStart() (++activityReferences == 1) (App enters Foreground??)

B.onResume()

That’s why we have an additional check of isActivityChangingConfigurations to avoid the scenario when the Activity is going through the Configuration changes.

Khorma answered 21/1, 2019 at 10:39 Comment(0)
R
5

You can use:

protected void onRestart ()

To differ between new starts and restarts.

enter image description here

Riedel answered 9/3, 2016 at 14:11 Comment(0)
U
3

Edit 2: What I've written below will not actually work. Google has rejected an app that includes a call to ActivityManager.getRunningTasks(). From the documentation, it is apparent that this API is for debugging and development purposes only. I'll be updating this post as soon as I have time to update the GitHub project below with a new scheme that uses timers and is almost as good.

Edit 1: I've written up a blog post and created a simple GitHub repository to make this really easy.

The accepted and top rated answer are both not really the best approach. The top rated answer's implementation of isApplicationBroughtToBackground() does not handle the situation where the Application's main Activity is yielding to an Activity that is defined in the same Application, but it has a different Java package. I came up with a way to do this that will work in that case.

Call this in onPause(), and it will tell you if your application is going into the background because another application has started, or the user has pressed the home button.

public static boolean isApplicationBroughtToBackground(final Activity activity) {
  ActivityManager activityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
  List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(1);

  // Check the top Activity against the list of Activities contained in the Application's package.
  if (!tasks.isEmpty()) {
    ComponentName topActivity = tasks.get(0).topActivity;
    try {
      PackageInfo pi = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_ACTIVITIES);
      for (ActivityInfo activityInfo : pi.activities) {
        if(topActivity.getClassName().equals(activityInfo.name)) {
          return false;
        }
      }
    } catch( PackageManager.NameNotFoundException e) {
      return false; // Never happens.
    }
  }
  return true;
}
Unstriped answered 2/8, 2012 at 23:59 Comment(1)
FYI, calling this in onStart() instead will avoid it being called when a simple dialog is thrown up from, for example, an alarm going off.Unstriped
I
3

I found a good method to detect application whether enter foreground or background. Here is my code. Hope this help you.

/**
 * Custom Application which can detect application state of whether it enter
 * background or enter foreground.
 *
 * @reference http://www.vardhan-justlikethat.blogspot.sg/2014/02/android-solution-to-detect-when-android.html
 */
 public abstract class StatusApplication extends Application implements ActivityLifecycleCallbacks {

public static final int STATE_UNKNOWN = 0x00;
public static final int STATE_CREATED = 0x01;
public static final int STATE_STARTED = 0x02;
public static final int STATE_RESUMED = 0x03;
public static final int STATE_PAUSED = 0x04;
public static final int STATE_STOPPED = 0x05;
public static final int STATE_DESTROYED = 0x06;

private static final int FLAG_STATE_FOREGROUND = -1;
private static final int FLAG_STATE_BACKGROUND = -2;

private int mCurrentState = STATE_UNKNOWN;
private int mStateFlag = FLAG_STATE_BACKGROUND;

@Override
public void onCreate() {
    super.onCreate();
    mCurrentState = STATE_UNKNOWN;
    registerActivityLifecycleCallbacks(this);
}

@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
    // mCurrentState = STATE_CREATED;
}

@Override
public void onActivityStarted(Activity activity) {
    if (mCurrentState == STATE_UNKNOWN || mCurrentState == STATE_STOPPED) {
        if (mStateFlag == FLAG_STATE_BACKGROUND) {
            applicationWillEnterForeground();
            mStateFlag = FLAG_STATE_FOREGROUND;
        }
    }
    mCurrentState = STATE_STARTED;

}

@Override
public void onActivityResumed(Activity activity) {
    mCurrentState = STATE_RESUMED;

}

@Override
public void onActivityPaused(Activity activity) {
    mCurrentState = STATE_PAUSED;

}

@Override
public void onActivityStopped(Activity activity) {
    mCurrentState = STATE_STOPPED;

}

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

}

@Override
public void onActivityDestroyed(Activity activity) {
    mCurrentState = STATE_DESTROYED;
}

@Override
public void onTrimMemory(int level) {
    super.onTrimMemory(level);
    if (mCurrentState == STATE_STOPPED && level >= TRIM_MEMORY_UI_HIDDEN) {
        if (mStateFlag == FLAG_STATE_FOREGROUND) {
            applicationDidEnterBackground();
            mStateFlag = FLAG_STATE_BACKGROUND;
        }
    }else if (mCurrentState == STATE_DESTROYED && level >= TRIM_MEMORY_UI_HIDDEN) {
        if (mStateFlag == FLAG_STATE_FOREGROUND) {
            applicationDidDestroyed();
            mStateFlag = FLAG_STATE_BACKGROUND;
        }
    }
}

/**
 * The method be called when the application been destroyed. But when the
 * device screen off,this method will not invoked.
 */
protected abstract void applicationDidDestroyed();

/**
 * The method be called when the application enter background. But when the
 * device screen off,this method will not invoked.
 */
protected abstract void applicationDidEnterBackground();

/**
 * The method be called when the application enter foreground.
 */
protected abstract void applicationWillEnterForeground();

}

Inveteracy answered 12/11, 2015 at 11:21 Comment(0)
H
3

you can simply call this method in your application class

ProcessLifecycleOwner.get().getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
                Log.e(TAG, "onStateChanged: " + event.toString());
            }
        });

Lifecycle.Event will simply return the state of the application

ON_CREATE
ON_START
ON_RESUME
ON_PAUSE
ON_STOP
ON_DESTROY
ON_ANY

it will return ON_PAUSE & ON_STOP when the app goes to background and will return ON_START & ON_RESUME when the app comes to the foreground

Hambley answered 12/9, 2019 at 6:47 Comment(0)
G
2

I was using this with Google Analytics EasyTracker, and it worked. It could be extended to do what you seek using a simple integer.

public class MainApplication extends Application {

    int isAppBackgrounded = 0;

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

    private void appBackgroundedDetector() {
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle bundle) {

            }

            @Override
            public void onActivityStarted(Activity activity) {
                EasyTracker.getInstance(MainApplication.this).activityStart(activity);
            }

            @Override
            public void onActivityResumed(Activity activity) {
                isAppBackgrounded++;
                if (isAppBackgrounded > 0) {
                    // Do something here
                }
            }

            @Override
            public void onActivityPaused(Activity activity) {
                isAppBackgrounded--;
            }

            @Override
            public void onActivityStopped(Activity activity) {
                EasyTracker.getInstance(MainApplication.this).activityStop(activity);
            }

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

            }

            @Override
            public void onActivityDestroyed(Activity activity) {

            }
        });
    }
}
Grudge answered 24/2, 2015 at 18:3 Comment(0)
F
2

Correct Answer here

Create class with name MyApp like below:

public class MyApp implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {

    private Context context;
    public void setContext(Context context)
    {
        this.context = context;
    }

    private boolean isInBackground = false;

    @Override
    public void onTrimMemory(final int level) {
        if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {


            isInBackground = true;
            Log.d("status = ","we are out");
        }
    }


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

    }

    @Override
    public void onActivityStarted(Activity activity) {

    }

    @Override
    public void onActivityResumed(Activity activity) {

        if(isInBackground){

            isInBackground = false;
            Log.d("status = ","we are in");
        }

    }

    @Override
    public void onActivityPaused(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {

    }

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

    }

    @Override
    public void onActivityDestroyed(Activity activity) {

    }

    @Override
    public void onConfigurationChanged(Configuration configuration) {

    }

    @Override
    public void onLowMemory() {

    }
}

Then, everywhere you want (better first activity launched in app), add the code below:

MyApp myApp = new MyApp();
registerComponentCallbacks(myApp);
getApplication().registerActivityLifecycleCallbacks(myApp);

Done! Now when the app is in the background, we get log status : we are out and when we go in app, we get log status : we are out

Ferrick answered 15/3, 2018 at 5:28 Comment(0)
A
2

Since I did not find any approach, which also handles rotation without checking time stamps, I thought I also share how we now do it in our app. The only addition to this answer https://mcmap.net/q/80321/-how-to-detect-when-an-android-app-goes-to-the-background-and-come-back-to-the-foreground is, that we also take the orientation into consideration.

class MyApplication : Application(), Application.ActivityLifecycleCallbacks {

   // Members

   private var mAppIsInBackground = false
   private var mCurrentOrientation: Int? = null
   private var mOrientationWasChanged = false
   private var mResumed = 0
   private var mPaused = 0

Then, for the callbacks we have the resume first:

   // ActivityLifecycleCallbacks

   override fun onActivityResumed(activity: Activity?) {

      mResumed++

      if (mAppIsInBackground) {

         // !!! App came from background !!! Insert code

         mAppIsInBackground = false
      }
      mOrientationWasChanged = false
    }

And onActivityStopped:

   override fun onActivityStopped(activity: Activity?) {

       if (mResumed == mPaused && !mOrientationWasChanged) {

       // !!! App moved to background !!! Insert code

        mAppIsInBackground = true
    }

And then, here comes the addition: Checking for orientation changes:

   override fun onConfigurationChanged(newConfig: Configuration) {

       if (newConfig.orientation != mCurrentOrientation) {
           mCurrentOrientation = newConfig.orientation
           mOrientationWasChanged = true
       }
       super.onConfigurationChanged(newConfig)
   }

That's it. Hope this helps someone :)

Anemo answered 5/7, 2018 at 13:9 Comment(0)
K
2

Here is the solution that by using a debouncing logic, makes sure we are not getting consecutive background/foreground events. So, it always reflects a stable state of backgrounding/foregrounding.

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import java.util.Timer
import java.util.TimerTask

/**
 * An observer class to listen on the app's lifecycle.
 */
class AppLifecycleObserver(
    private val onAppGoesToBackground: () -> Unit = {},
    private val onAppEntersForeground: () -> Unit = {}
) : LifecycleEventObserver {

    private val debounce = DebouncingTimer(timeout = 10)

    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
        debounce.refresh {
            when (event.targetState) {
                Lifecycle.State.CREATED -> onAppGoesToBackground()
                Lifecycle.State.RESUMED -> onAppEntersForeground()
                else -> Unit
            }
        }
    }

    fun attach() {
        ProcessLifecycleOwner.get().lifecycle.addObserver(this)
    }

    fun detach() {
        ProcessLifecycleOwner.get().lifecycle.removeObserver(this)
    }

    private class DebouncingTimer(private val timeout: Long) {

        private var timer: Timer? = null

        fun refresh(job: () -> Unit) {
            timer?.cancel()
            timer = Timer()
            timer?.schedule(object : TimerTask() {
                override fun run() = job.invoke()
            }, timeout)
        }
    }
}

Just needs to create an instance of AppLifecycleObserver:

private val appLifecycleObserver = AppLifecycleObserver(
        onAppGoesToBackground = { // do whatever... },
        onAppEntersForeground = { // do whatever... }
    )
// Attach the observer when it is needed:
appLifecycleObserver.attach()

// Remove when there is no need to it:
appLifecycleObserver.detach()

Don't forget to add a proper version of the dependency:

implementation("androidx.lifecycle:lifecycle-process:$lifecycle_version")
Kibitka answered 28/1, 2022 at 13:39 Comment(0)
W
2

LifecycleObserver is deprecated. Use DefaultLifecycleObserver instead:

public class YourApplication extends Application implements DefaultLifecycleObserver {

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

    @Override
    public void onStart(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onStart(owner);
    }

    @Override
    public void onResume(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onResume(owner);
    }

    @Override
    public void onPause(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onPause(owner);
    }

    @Override
    public void onStop(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onStop(owner);
    }

    @Override
    public void onDestroy(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onDestroy(owner);
    }
}

Dependencies:

  implementation 'androidx.lifecycle:lifecycle-common:2.5.1'
  implementation 'androidx.lifecycle:lifecycle-process:2.5.1'
Wilbur answered 15/9, 2022 at 20:14 Comment(0)
D
1

What I did is make sure that all in-app activities are launched with startActivityForResult then checking if onActivityResult was called before onResume. If it wasn't, it means we just returned from somewhere outside our app.

boolean onActivityResultCalledBeforeOnResume;

@Override
public void startActivity(Intent intent) {
    startActivityForResult(intent, 0);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);
    onActivityResultCalledBeforeOnResume = true;
}

@Override
protected void onResume() {
    super.onResume();
    if (!onActivityResultCalledBeforeOnResume) {
        // here, app was brought to foreground
    }
    onActivityResultCalledBeforeOnResume = false;
}
Dianetics answered 4/7, 2012 at 8:54 Comment(0)
V
1

My solution was inspired by @d60402's answer and also relies on a time-window, but not using the Timer:

public abstract class BaseActivity extends ActionBarActivity {

  protected boolean wasInBackground = false;

  @Override
  protected void onStart() {
    super.onStart();
    wasInBackground = getApp().isInBackground;
    getApp().isInBackground = false;
    getApp().lastForegroundTransition = System.currentTimeMillis();
  }

  @Override
  protected void onStop() {
    super.onStop();
    if( 1500 < System.currentTimeMillis() - getApp().lastForegroundTransition )
      getApp().isInBackground = true;
  }

  protected SingletonApplication getApp(){
    return (SingletonApplication)getApplication();
  }
}

where the SingletonApplication is an extension of Application class:

public class SingletonApplication extends Application {
  public boolean isInBackground = false;
  public long lastForegroundTransition = 0;
}
Vaporimeter answered 8/5, 2015 at 11:12 Comment(0)
C
1

i know its a little late but i think all these answers do have some problems while i did it like below and that works perfect.

create a activity life cycle callback like this:

 class ActivityLifeCycle implements ActivityLifecycleCallbacks{

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

    }

    @Override
    public void onActivityStarted(Activity activity) {

    }

    Activity lastActivity;
    @Override
    public void onActivityResumed(Activity activity) {
        //if (null == lastActivity || (activity != null && activity == lastActivity)) //use this condition instead if you want to be informed also when  app has been killed or started for the first time
        if (activity != null && activity == lastActivity) 
        {
            Toast.makeText(MyApp.this, "NOW!", Toast.LENGTH_LONG).show();
        }

        lastActivity = activity;
    }

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

    }
}

and just register it on your application class like below:

public class MyApp extends Application {

@Override
public void onCreate() {
    super.onCreate();
    registerActivityLifecycleCallbacks(new ActivityLifeCycle());
}
Caribou answered 15/5, 2017 at 4:3 Comment(3)
This gets called all the time on each activity. How can I use this if for example I want to detect user online statusAnabranch
thats what the question wants. it only gets called when you go to home screen and return to any activity.Caribou
if you mean internet connectivity i think its better to check that when you need it. if you need to call an api check the internet connection just before calling.Caribou
S
1

This appears to be one of the most complicated questions in Android since (as of this writing) Android doesn't have iOS equivalents of applicationDidEnterBackground() or applicationWillEnterForeground() callbacks. I used an AppState Library that was put together by @jenzz.

[AppState is] a simple, reactive Android library based on RxJava that monitors app state changes. It notifies subscribers every time the app goes into background and comes back into foreground.

It turned out this is exactly what I needed, especially because my app had multiple activities so simply checking onStart() or onStop() on an activity wasn't going to cut it.

First I added these dependencies to gradle:

dependencies {
    compile 'com.jenzz.appstate:appstate:3.0.1'
    compile 'com.jenzz.appstate:adapter-rxjava2:3.0.1'
}

Then it was a simple matter of adding these lines to an appropriate place in your code:

//Note that this uses RxJava 2.x adapter. Check the referenced github site for other ways of using observable
Observable<AppState> appState = RxAppStateMonitor.monitor(myApplication);
//where myApplication is a subclass of android.app.Application
appState.subscribe(new Consumer<AppState>() {
    @Override
    public void accept(@io.reactivex.annotations.NonNull AppState appState) throws Exception {
        switch (appState) {
            case FOREGROUND:
                Log.i("info","App entered foreground");
                break;
            case BACKGROUND:
                Log.i("info","App entered background");
                break;
        }
    }
});

Depending on how you subscribe to the observable, you may have to unsubscribe from it to avoid memory leaks. Again more info on the github page.

Stereoscopic answered 22/9, 2017 at 20:5 Comment(0)
Z
1

This is the modified version of @d60402's answer: https://mcmap.net/q/80321/-how-to-detect-when-an-android-app-goes-to-the-background-and-come-back-to-the-foreground

Do everything mentioned there. But instead of having a Base Activity and making that as a parent for every activity and the overriding the onResume() and onPause, do the below:

In your application class, add the line:

registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback);

This callback has all the activity lifecycle methods and you can now override onActivityResumed() and onActivityPaused().

Take a look at this Gist: https://gist.github.com/thsaravana/1fa576b6af9fc8fff20acfb2ac79fa1b

Zellner answered 25/9, 2017 at 10:34 Comment(0)
U
1

You can achieve this easily with the help of ActivityLifecycleCallbacks and ComponentCallbacks2 something like below.

Create a class AppLifeCycleHandler implementing above said interfaces.

package com.sample.app;

import android.app.Activity;
import android.app.Application;
import android.content.ComponentCallbacks2;
import android.content.res.Configuration;
import android.os.Bundle;

/**
 * Created by Naveen on 17/04/18
 */
public class AppLifeCycleHandler
    implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {

  AppLifeCycleCallback appLifeCycleCallback;

  boolean appInForeground;

  public AppLifeCycleHandler(AppLifeCycleCallback appLifeCycleCallback) {
    this.appLifeCycleCallback = appLifeCycleCallback;
  }

  @Override
  public void onActivityResumed(Activity activity) {
    if (!appInForeground) {
      appInForeground = true;
      appLifeCycleCallback.onAppForeground();
    }
  }

  @Override
  public void onTrimMemory(int i) {
    if (i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
      appInForeground = false;
      appLifeCycleCallback.onAppBackground();
    }
  }

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

  }

  @Override
  public void onActivityStarted(Activity activity) {

  }

  @Override
  public void onActivityPaused(Activity activity) {

  }

  @Override
  public void onActivityStopped(Activity activity) {

  }

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

  }

  @Override
  public void onActivityDestroyed(Activity activity) {

  }

  @Override
  public void onConfigurationChanged(Configuration configuration) {

  }

  @Override
  public void onLowMemory() {

  }

  interface AppLifeCycleCallback {

    void onAppBackground();

    void onAppForeground();
  }
}

In your class which extends Application implement AppLifeCycleCallback to get the callbacks when app switches between foreground and background. Something like below.

public class BaseApplication extends Application implements AppLifeCycleHandler.AppLifeCycleCallback{

    @Override
    public void onCreate() {
        super.onCreate();
        AppLifeCycleHandler appLifeCycleHandler = new AppLifeCycleHandler(this);
        registerActivityLifecycleCallbacks(appLifeCycleHandler);
        registerComponentCallbacks(appLifeCycleHandler);
    }

    @Override
    public void onAppBackground() {
        Log.d("LifecycleEvent", "onAppBackground");
    }

    @Override
    public void onAppForeground() {
        Log.d("LifecycleEvent", "onAppForeground");
    }
}

Hope this helps.

EDIT As an alternative you can now use Life cycle aware architecture component.

Ulita answered 17/4, 2018 at 13:7 Comment(0)
I
1

We can expand this solution using LiveData:

class AppForegroundStateLiveData : LiveData<AppForegroundStateLiveData.State>() {

    private var lifecycleListener: LifecycleObserver? = null

    override fun onActive() {
        super.onActive()
        lifecycleListener = AppLifecycleListener().also {
            ProcessLifecycleOwner.get().lifecycle.addObserver(it)
        }
    }

    override fun onInactive() {
        super.onInactive()
        lifecycleListener?.let {
            this.lifecycleListener = null
            ProcessLifecycleOwner.get().lifecycle.removeObserver(it)
        }
    }

    internal inner class AppLifecycleListener : LifecycleObserver {

        @OnLifecycleEvent(Lifecycle.Event.ON_START)
        fun onMoveToForeground() {
            value = State.FOREGROUND
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
        fun onMoveToBackground() {
            value = State.BACKGROUND
        }
    }

    enum class State {
        FOREGROUND, BACKGROUND
    }
}

Now we can subscribe to this LiveData and catch the needed events. For example:

appForegroundStateLiveData.observeForever { state ->
    when(state) {
        AppForegroundStateLiveData.State.FOREGROUND -> { /* app move to foreground */ }
        AppForegroundStateLiveData.State.BACKGROUND -> { /* app move to background */ }
    }
}
Immesh answered 24/4, 2019 at 19:52 Comment(1)
@OnLifecycleEvent is deprecated. developer.android.com/jetpack/androidx/releases/…Zarger
S
1

There are three ways through which you can achieve this:

  • Single Activity architecture
  • ActivityLifecycleCallback
  • LifecycleObserver and ProcessLifecycleOwner

Have written an article in detail on this over here. Hope it helps.

Selfrevealing answered 14/6, 2020 at 19:46 Comment(0)
E
1

An example to detect app from background to foreground in Activity (or any class) using ProcessLifecycleOwner.
When the application start, I cache the start time and then in each activity I will check with application time to know if activity start at first time or from background

class MyApplication : Application(), LifecycleObserver {

    var appStartBeginTime: Long? = null

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

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onMoveToForeground() {
        Log.i("TAG", "onMoveToForeground")
        appStartBeginTime = System.currentTimeMillis()
    }
}

LoginActivity

class LoginActivity : AppCompatActivity() {
    var localAppStartBeginTime: Long? = null

    ...
    
    // Detect in onResume() instead of onStart because 
    // onMoveToForeground() in MyApplication will fired before onStart 
    override fun onResume() {
        super.onResume()
        if (isOpenedFirstTimeOrFromBackground()) {
            Log.i("TAG", "open first time or from background")

            // do something: eg, call API
        } else {
            Log.i("TAG", "on in another time")
        }
    }

    private fun isOpenedFirstTimeOrFromBackground(): Boolean {
        val globalStartBeginTime = (application as MyApplication).appStartBeginTime
        if (localAppStartBeginTime != globalStartBeginTime) {
            localAppStartBeginTime = globalStartBeginTime
            return true
        }
        return false
    }
}

AndroidManifest

<manifest ...>

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

</manifest>

DEMO https://github.com/PhanVanLinh/AndroidDetectAppFromBackgroundToForeground

Estate answered 20/3, 2021 at 2:17 Comment(1)
@OnLifecycleEvent is deprecated. developer.android.com/jetpack/androidx/releases/…Zarger
L
0

These answers don't seem to be correct. These methods are also called when another activity starts and ends. What you can do is keep a global flag (yes, globals are bad:) and set this to true each time you start a new activity. Set it to false in the onCreate of each activity. Then, in the onPause you check this flag. If it's false, your app is going into the background, or it's getting killed.

Lerma answered 28/2, 2012 at 13:7 Comment(2)
I didn't talk about a database... what do you mean?Lerma
i'm supporting your answer. even though we can save that flag value in the database while on pause call it is not the good solution..Furry
S
0

This is my solution https://github.com/doridori/AndroidUtils/blob/master/App/src/main/java/com/doridori/lib/app/ActivityCounter.java

Basically involved counting the lifecycle methods for all Activity's with a timer to catch cases where there is no activity currently in the foreground but the app is (i.e. on rotation)

Scuppernong answered 21/11, 2014 at 14:26 Comment(0)
M
0

Here is my solution. Just register this ActivityLifecycleCallbacks in your main Application class. In the comments, I mention a user profile Activity edge case. That Activity is simply one with transparent edges.

/**
 * This class used Activity lifecycle callbacks to determine when the application goes to the
 * background as well as when it is brought to the foreground.
 */
public class Foreground implements Application.ActivityLifecycleCallbacks
{
    /**
     * How long to wait before checking onStart()/onStop() count to determine if the app has been
     * backgrounded.
     */
    public static final long BACKGROUND_CHECK_DELAY_MS = 500;

    private static Foreground sInstance;

    private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
    private boolean mIsForeground = false;
    private int mCount;

    public static void init(final Application application)
    {
        if (sInstance == null)
        {
            sInstance = new Foreground();
            application.registerActivityLifecycleCallbacks(sInstance);
        }
    }

    public static Foreground getInstance()
    {
        return sInstance;
    }

    public boolean isForeground()
    {
        return mIsForeground;
    }

    public boolean isBackground()
    {
        return !mIsForeground;
    }

    @Override
    public void onActivityStarted(final Activity activity)
    {
        mCount++;

        // Remove posted Runnables so any Meteor disconnect is cancelled if the user comes back to
        // the app before it runs.
        mMainThreadHandler.removeCallbacksAndMessages(null);

        if (!mIsForeground)
        {
            mIsForeground = true;
        }
    }

    @Override
    public void onActivityStopped(final Activity activity)
    {
        mCount--;

        // A transparent Activity like community user profile won't stop the Activity that launched
        // it. If you launch another Activity from the user profile or hit the Android home button,
        // there are two onStops(). One for the user profile and one for its parent. Remove any
        // posted Runnables so we don't get two session ended events.
        mMainThreadHandler.removeCallbacksAndMessages(null);
        mMainThreadHandler.postDelayed(new Runnable()
        {
            @Override
            public void run()
            {
                if (mCount == 0)
                {
                    mIsForeground = false;
                }
            }
        }, BACKGROUND_CHECK_DELAY_MS);
    }

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

    }

    @Override
    public void onActivityResumed(final Activity activity)
    {

    }

    @Override
    public void onActivityPaused(final Activity activity)
    {

    }

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

    }

    @Override
    public void onActivityDestroyed(final Activity activity)
    {

    }
}
Mazza answered 12/2, 2016 at 2:42 Comment(0)
K
0

My app needs to "reboot" after return from background - show a series of activities, according to client solicitations. After extensive search on how to manage the background/foreground transitions (treated very differently between iOS and Android), I crossed this question. Found very useful help here, specially from the most voted answer and the one flagged as correct. However, simply reinstantiate the root activity EVERY TIME the app enters foreground looked too annoying, when you think about UX. The solution that worked for me, and the one I think's most adequated - based on the Youtube and Twitter apps functionality - was to combine the answers from @GirishNair and @d60402: Calling the timer when the app's trimming memory, as follows:

@Override
public void onTrimMemory(int level) {
    if (stateOfLifeCycle.equals("Stop")) {
        startActivityTransitionTimer();
    }

    super.onTrimMemory(level);
}

My Timer limit is set to 30 seconds - I'm thinking about increasing this a little.

private final long MAX_ACTIVITY_TRANSITION_TIME = 30000;

And when app goes into foreground, is relaunched, or the app's destroyed, call the method to cancel timer.

On App extension:

@Override
public void onActivityCreated(Activity activity, Bundle arg1) {
    stopActivityTransitionTimer();
    stateOfLifeCycle = "Create";
}

@Override
public void onActivityDestroyed(Activity activity) {
    stopActivityTransitionTimer();
    stateOfLifeCycle = "Destroy";
}

On the activity (preferably on a base activity, inherited by the others):

@Override
protected void onStart() {
    super.onStart();
    if (App.wasInBackground) {
        stopActivityTransitionTimer();
    }
}

In my case, when app goes foreground after the max time, a new task is created, so the stopActivityTransitionTimer() is called upon onActivityCreated() or onActivityDestroyed(), in the app extension class - turning unnecessary to call the method in an activity. Hope it helps.

Kreis answered 4/5, 2016 at 12:34 Comment(0)
G
0

How about this solution

public class BaseActivity extends Activity
{

    static String currentAct = "";

    @Override
    protected void onStart()
    {
        super.onStart();

        if (currentAct.equals(""))
            Toast.makeText(this, "Start", Toast.LENGTH_LONG).show();

        currentAct = getLocalClassName();
    }

    @Override
    protected void onStop()
    {
        super.onStop();

        if (currentAct.equals(getLocalClassName()))
        {
            currentAct = "";
            Toast.makeText(this, "Stop", Toast.LENGTH_LONG).show();
        }
    }
}

All Activity need to extends BaseActivity.

When an activity call another (A->B) then currentAct is not equal getLocalClassName() because the onStart() of the second activity (B) is called before the onStop() of the first (A) (https://developer.android.com/guide/components/activities.html#CoordinatingActivities).

When the user press the home button or change between application will just call onStop() and then currentAct is equal getLocalClassName().

Gauhati answered 10/3, 2017 at 2:6 Comment(0)
Z
0

By using below code I'm able to get my app foreground or background state.

For more detail about it's working, strong text click here

import android.content.ComponentCallbacks2;
import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

private Context context;
private Toast toast;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    context = this;
}

private void showToast(String message) {
    //If toast is already showing cancel it
    if (toast != null) {
        toast.cancel();
    }

    toast = Toast.makeText(context, message, Toast.LENGTH_SHORT);
    toast.show();
}

@Override
protected void onStart() {
    super.onStart();
    showToast("App In Foreground");
}

@Override
public void onTrimMemory(int level) {
    super.onTrimMemory(level);
    if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
        showToast("App In Background");
    }
  }
}
Zephan answered 28/2, 2018 at 9:49 Comment(1)
OnTrimMemory is not called when the user presses the back button and the app goes to the background.Rafi
H
0

I managed to monitor app navigation going to background and back to foreground by implementing a BaseActivity that exploits the use of onResume, onPause and onStop activity callbacks. Here is my implementations.

override fun onResume() {
    super.onResume()
    if (AppActivityState.state == AppState.ON_LAUNCHED) {
        // We are in the first launch.
        onLaunched()
    } else {
        if (AppActivityState.state == AppState.ON_BACKGROUND) {
            // We came from background to foreground.
            AppActivityState.state = AppState.ON_FOREGROUND
            onForeground()
        } else {
            // We are just navigating through pages.
            AppActivityState.state = AppState.RESUMED
        }
    }
}

override fun onPause() {
    super.onPause()
    // If state is followed by onStop then it means we will going to background.
    AppActivityState.state = AppState.PAUSED
}

override fun onStop() {
    super.onStop()

    // App will go to background base on the 'pause' cue.
    if (AppActivityState.state == AppState.PAUSED) {
        AppActivityState.state = AppState.ON_BACKGROUND
        onBackground()
    }
}

After creating BaseActivity, you just have to extend this activity to any activity on your app.

In these type of implementation, you can accurately detect the following: - onBackground > app will go to background - onForeground > app will go back to foreground - onLaunch > app just opened

I hope this will help you :)

Harvell answered 28/11, 2018 at 5:4 Comment(0)
D
0

I like the ProcessLifecycleOwner approach, but actually one can skip all of that, because in an Activity's onCreate() method, one can easily determine if it's the first or a subsequent run:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState == null) {
        /* savedInstanceState is always null on first run */
    } else {
        /* it's a subsequent run */
    }
}
Digiovanni answered 20/3, 2021 at 2:44 Comment(0)
B
-1

I'm using this solution: http://nathanael.hevenet.com/android-dev-detecting-when-your-app-is-in-the-background-across-activities/

In short- Build a dedicate service that every activity report him about each lifecycle event, and this service get the info about the status of the app.

Very much like @oldschool4664 solution, but cleaner in my opinion

Bullen answered 7/8, 2013 at 15:9 Comment(0)
F
-3

The principal problem is that you have to get an specific behavior when you start an activity from background. If you override your onPause() and onResume() methods, you'll have a close answer, but not the solution. The problem is that onPause() and onResume() methods are called even if you don't minimize your application, they can be called when you start an activity and later you press the back button to return to your activity. To eliminate that problem and to know really when your application comes from background, you must to get the running process and compare with your process:

private boolean isApplicationBroughtToBackground() {
    ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> tasks = am.getRunningTasks(1);
    if (!tasks.isEmpty()) {
        ComponentName topActivity = tasks.get(0).topActivity;
        if (!topActivity.getPackageName().equals(getPackageName())) {
            return true;
        }
    }
    return false;
}

Now you have to declare a boolean variable:

public boolean wasPaused = false;

And ask when your activity comes to background:

@Override
public void onPause(){
    super.onPause();
    if(isApplicationBroughtToBackground())
        wasPaused = true;
}

Now, when your activity comes to the screen again, ask in onResume() method:

@Override
public void onResume(){
    super.onResume();
    if(wasPaused){
        lockScreen(true);
    }
    wasPaused = false;
}

And this is it. Now, when your activity comes to background, and later the user brings it to foreground, the lock screen will appear.

If you want to repeat this behavior for whatever activity of your app, you have to create an activity (could be BaseActivity), put this methods, and all your activities have to inherit from BaseActivity.

I hope that this help to you.

Greetings!

Fare answered 4/2, 2013 at 18:45 Comment(1)
As stated elsewhere on this page, getRunningTasks() is not intended for production code, and apparently, apps have been pulled for using it.Cuspid

© 2022 - 2024 — McMap. All rights reserved.