Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OnPause and OnStop() called immediately after starting activity

I have an activity that needs to turn screen on(if offed) when it is started. So in onCreate, I have:

this.getWindow().setFlags(             WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON                     | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED                     | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON,             WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON                     | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED                     | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); 

Using this with help of wakelock in broadcasr receiver , I am able to cause my activity to display whenever it is started from broadcast receiver.

But problem is very strange, activity lifecycle calls in this manner, onPause() and onResume immediately after starting activity

  1. onCreate
  2. onStart
  3. onResume
  4. onPause
  5. onStop
  6. onStart
  7. onResume

So the problem is on start and on resume calling twice, with on stop also calling, I want to implement some logic in onStop() but, with such behavior app will not work correctly.

Edit

I found problem is only due to flag FLAG_SHOW_WHEN_LOCKED. and when device is locked. and it only happens when device is locked before activity is starting.

P.S I am using alarm manager with broadcast receiver, and then starts activity from broadcast receiver.

like image 826
Haris Avatar asked Aug 18 '14 18:08

Haris


People also ask

Is onPause always called before onStop?

onPause() is always called. This is guaranteed. If you need to save any state in your activity you need to save it in onPause() . onStop() may be called after onPause() , or it may not.

When onPause method is called when?

onPause() method of an activity is call when you receive a phone call. Otherwise in lots of cases onPause() is always call with onStop() . Example like when you press home button, call another intent and more like when your activity is in background.

When Ondestroy () is called before onPause () and onStop () in an Android application?

onPause() and onStop() will not be invoked if finish() is called from within the onCreate() method. This might occur, for example, if you detect an error during onCreate() and call finish() as a result. In such a case, though, any cleanup you expected to be done in onPause() and onStop() will not be executed.

In which scenario does the onStop () method invokes in the activity lifecycle?

onStart() can be called several times during an application's lifecycle. For example, this method can be called when a user opens another activity and then navigates back to the previous activity. During the activity's lifecycle, the onStop() function is called. This means that some resources are released.


1 Answers

  • 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     } } 
like image 183
Manish Mulimani Avatar answered Sep 21 '22 05:09

Manish Mulimani