OnPause and OnStop() called immediately after starting activity
Solution 1:
- Let us understand why the lifecycle methods are called multiple times.
Here is an important code comment documented in ActivityThread, which is responsible for executing the activities of the application process.
We accomplish this by going through the normal startup (because activities expect to go through onResume() the first time they run, before their window is displayed), and then pausing it.
Right after onResume
, the activity window is attached to the window manager and onAttachedtoWindow
is invoked. If the screen is on, the activity window will get focus and onWindowFocusChanged
is invoked with true
parameter. From docs:
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
In the reported issue, the screen if off. Hence activity window will not get focus, which results in activity's onPause
method getting called followed by onStop
method, as the activity window is not visible.
Since WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
flag is set on activity window, the window manager service turns on the screen using power manager api. Following is the WindowManagerService code:
public int relayoutWindow(...) {
...
toBeDisplayed = !win.isVisibleLw();
...
if (toBeDisplayed) {
...
if ((win.mAttrs.flags
& WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) != 0) {
if (DEBUG_VISIBILITY) Slog.v(TAG,
"Relayout window turning screen on: " + win);
win.mTurnOnScreen = true;
}
...
if (mTurnOnScreen) {
if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
mPowerManager.wakeUp(SystemClock.uptimeMillis());
mTurnOnScreen = false;
}
...
}
After the screen turns on onStart
and onPause
are called again.
Hence : onCreate - onStart - onResume - onPause - onStop - onStart - onPause
.
This can be verified by locking the device and starting the activity using adb
command or eclipse
.
- Ideal Solution
If you start a task in onCreate
you need to stop it in onDestory
(if the task is still pending). Similarly for onStart
it would be onStop
and for onResume
it would be onPause
.
- Workaround
If you can't follow the above protocol, you can check the status of activity window focus using hasWindowFocus in onPause
method. Normally the activity window focus status will be true in onPause
. In scenarios like screen is off or screen is on with keyguard displayed, the activity window focus will be false in onPause
.
boolean mFocusDuringOnPause;
public void onPause() {
super.onPause;
mFocusDuringOnPause = hasWindowFocus();
}
public void onStop() {
super.onStop();
if(mFocusDuringOnPause) {
// normal scenario
} else {
// activity was started when screen was off / screen was on with keygaurd displayed
}
}
Solution 2:
Add android:configChanges="keyboardHidden|orientation|screenSize"
to you Activity
in your Manifest
. This may solve your problem.
Solution 3:
The workaround by Manish Mulimani worked for me, except I first check for the window focus and then call through to the super.onPause():
public void onPause() {
mFocusDuringOnPause = hasWindowFocus();
super.onPause();
}
public void onStop() {
super.onStop();
if (mFocusDuringOnPause) {
// normal scenario
} else {
// activity was started when screen was off or screen was on with keyguard displayed
}
}