Search code examples
androidandroid-activityandroid-orientation

Multiple onStop / onResume calls in Android activity


Background

When putting my application to background (navigating elsewhere on my Android phone), onStop() is called once, just as expected (Activity lifecycle)

Question rationale: the onStop() contains code which developer expects to be run once.

Question

Why, in case I am locking my phone (single power button press) while in my application's activity - onStop() gets called 3 times?

Update

CASE #1

05-28 14:06:29.322 24347-24347/com... D/DEBUG: onCreate
05-28 14:06:29.380 24347-24347/com... D/DEBUG: onStart
05-28 14:06:29.380 24347-24347/com... D/DEBUG: onResume  

While activity is running, I navigate elsewhere off the app:

05-28 14:06:31.954 24347-24347/com... D/DEBUG: onStop  

At this point I navigate back to the app and open it:

05-28 14:06:34.314 24347-24347/com... D/DEBUG: onStart
05-28 14:06:34.314 24347-24347/com... D/DEBUG: onResume  

CASE #2

05-28 14:09:01.411 24347-24347/com... D/DEBUG: onCreate
05-28 14:09:01.453 24347-24347/com... D/DEBUG: onStart
05-28 14:09:01.453 24347-24347/com... D/DEBUG: onResume  

At this point I lock my device:

05-28 14:35:55.017 30961-30961/com... D/DEBUG: onStop
05-28 14:35:55.278 30961-30961/com... D/DEBUG: onDestroy
05-28 14:35:55.367 30961-30961/com... D/DEBUG: onCreate
05-28 14:35:55.411 30961-30961/com... D/DEBUG: onStart
05-28 14:35:55.419 30961-30961/com... D/DEBUG: onResume
05-28 14:35:55.440 30961-30961/com... D/DEBUG: onStop
05-28 14:35:55.441 30961-30961/com... D/DEBUG: onDestroy
05-28 14:35:55.451 30961-30961/com... D/DEBUG: onCreate
05-28 14:35:55.493 30961-30961/com... D/DEBUG: onStart
05-28 14:35:55.502 30961-30961/com... D/DEBUG: onResume
05-28 14:35:55.830 30961-30961/com... D/DEBUG: onStop
05-28 14:35:55.969 30961-30961/com... D/DEBUG: onDestroy
05-28 14:35:56.004 30961-30961/com... D/DEBUG: onCreate
05-28 14:35:56.044 30961-30961/com... D/DEBUG: onStart
05-28 14:35:56.052 30961-30961/com... D/DEBUG: onResume

I unlock it to see the activity which is still present:

05-28 14:39:38.225 30961-30961/com... D/DEBUG: onResume
05-28 14:39:38.415 30961-30961/com... D/DEBUG: onStop
05-28 14:39:38.416 30961-30961/com... D/DEBUG: onDestroy
05-28 14:39:38.465 30961-30961/com... D/DEBUG: onCreate
05-28 14:39:38.610 30961-30961/com... D/DEBUG: onStart
05-28 14:39:38.624 30961-30961/com... D/DEBUG: onResume

Not sure if it is relevant, but the activity makes use of VLC library to play video. Same result is reached whether the video is currently on playback or not.

Update

My activity, in AndroidManifest.xml is defined with android:screenOrientation="sensorLandscape". The problem disappears once the property is removed (android:screenOrientation="unspecified").


Solution

  • Correct issue was pointed out by David Wasser

    The cause of activity being destroyed and re-created is similar to change of orientation.
    My activity is using android:screenOrientation="sensorLandscape", and I had no clue the "orientation" might change when destroying the activity.

    My application depends both on onStop() and onResume() calls, so I will implement onResume() as they are similar.

    Solution based on Saving the Instance State

    private boolean onResumeCalledAlready;
    private String ON_RESUME_CALLED_PREFERENCE_KEY = "onResumeCalled";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Record onResume not called yet
        if (savedInstanceState != null) {
            // Restore value of members from saved state
            onResumeCalledAlready = savedInstanceState.getBoolean(ON_RESUME_CALLED_PREFERENCE_KEY);
        } else {
            onResumeCalledAlready = false;
        }
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        if (!onResumeCalledAlready) {
            onResumeCalledAlready = true;
            // Do once
            callMeOnlyOnce();
        }
        // Everything else might be called multiple times
    }
    
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        // Save current onResumeCalledAlready state
        outState.putBoolean(ON_RESUME_CALLED_PREFERENCE_KEY, onResumeCalledAlready);
        super.onSaveInstanceState(outState);
    }