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

后端 未结 30 1352
独厮守ぢ
独厮守ぢ 2020-11-22 00:56

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

相关标签:
30条回答
  • 2020-11-22 01:24

    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.

    0 讨论(0)
  • 2020-11-22 01:24

    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.

    0 讨论(0)
  • 2020-11-22 01:24

    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.

    0 讨论(0)
  • 2020-11-22 01:25

    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.

    0 讨论(0)
  • 2020-11-22 01:26

    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"
    
    0 讨论(0)
  • 2020-11-22 01:27

    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 {
        ...
    }
    
    0 讨论(0)
提交回复
热议问题