androidandroid-lifecycleactivity-lifecycle

Activity onStop is received for previous activity instance after onResume during fast transition


The Launcher activity is responsible to handle the widgets of Homescreen. In onStart it calls appWidgetHost.startListening and in onStop it calls appWidgetHost.stopListening(). The expectation is when the activity is in foreground, the widgets should receive the updates from the widget providers . When it switches to background, it should stop receiving the widget updates.

The activity code is as below-

    protected void onResume() {
        currentState = ActivityState.RESUMED;
        super.onResume();
        Log.d(TAG, "onResume currentState:"+currentState+" object:"+this);
    }
    @Override
    protected void onPause() {
        currentState = ActivityState.PAUSED;
        super.onPause();
        Log.d(TAG, "onPause currentState:"+currentState+" object:"+this);
    }

    @Override
    protected void onStart() {
        currentState = ActivityState.STARTED;
        super.onStart();
        Log.d(TAG, "onStart currentState:"+currentState+" object:"+this);
        if (appWidgetHost != null) {
            Log.d(TAG, "onStart appWidgetHost startListening = " + appWidgetHost);
                appWidgetHost.startListening();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop() currentState:" + currentState+" object:"+this);
        currentState = ActivityState.STOPPED;

        if (appWidgetHost != null) {
            appWidgetHost.stopListening();
        }
    }

In an ideal situation, when we switch to a different application and switch back to Homescreen, the activity onStart is called and the widgets are loaded.

But if we perform the transition very quickly, sometimes it ends up getting onStart for the current activity instance and then onStop state for the previous activity instance. So even though the activity is in foreground, it stops listening the widget updates. In this case the widgets are not updated. From the log, we can see the activity onStop is from the previous instance.

Log for the error scenario:

LauncherActivity: onPause currentState:PAUSED object:com.bosch.apps.homescreen.ui.LauncherActivity@11a9396 launchHomeScreen LauncherActivity: onCreate: object:com.bosch.apps.homescreen.ui.LauncherActivity@ebd5de9 LauncherActivity: onStart currentState:STARTED object:com.bosch.apps.homescreen.ui.LauncherActivity@ebd5de9 LauncherActivity: onResume currentState:RESUMED object:com.bosch.apps.homescreen.ui.LauncherActivity@ebd5de9 LauncherActivity: onStop() currentState:PAUSED object:com.bosch.apps.homescreen.ui.LauncherActivity@11a9396

How should we handle this situation?


Solution

  • This is a valid transition. There is no promise about the order of onStart and onStop of the previous. In fact getting onStart of the new one before onStop of the old one is more likely than not. I'd make a smarter onStartListening and onStopListening function. A simple solution is to reference count, make each startListening call increase a variable, and onStop decrease it. Only stop listening if it actually hits 0.