启动活动后立即调用OnPause和OnStop()

时间:2014-08-18 18:37:25

标签: android android-activity wakelock activity-lifecycle

我有一项活动需要在启动时打开屏幕(如果已关闭)。 所以在onCreate中,我有:

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);

在广播接收器的wakelock的帮助下使用它,我能够在广播接收器启动时显示我的活动。

但问题很奇怪,活动生命周期以这种方式调用,onPause()和onResume在启动活动后立即调用

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

  8. 所以问题出在启动和继续调用两次,在停止也调用,我想在onStop()中实现一些逻辑,但是,这样的行为app将无法正常工作。

    修改

    我发现问题只是由于标志FLAG_SHOW_WHEN_LOCKED。当设备被锁定时它只会在活动开始前锁定设备时发生。

    P.S我正在使用带有广播接收器的报警管理器,然后从广播接收器开始活动。

6 个答案:

答案 0 :(得分:43)

  • 让我们了解为什么多次调用生命周期方法。

以下是ActivityThread中记录的重要代码注释,它负责执行应用程序进程的活动。

  

我们通过正常启动来实现这一目标(因为   活动期望第一次运行onResume(),   在显示它们的窗口之前),然后暂停它。

onResume之后,活动窗口附加到窗口管理器,并调用onAttachedtoWindow。如果屏幕已打开,则活动窗口将获得焦点,并使用onWindowFocusChanged参数调用true。来自docs

  

请记住,onResume不是您的最佳指标   活动对用户可见;一个系统窗口,如键盘锁   可能在前面。使用onWindowFocusChanged(boolean)来确定   您的活动对用户可见

在报告的问题中,屏幕如果关闭。因此,活动窗口不会获得焦点,这导致活动的onPause方法被调用,后跟onStop方法,因为活动窗口不可见。

由于在活动窗口上设置了WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON标志,因此窗口管理器服务使用电源管理器api打开屏幕。以下是WindowManagerService代码:

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;
        }
        ...
}

屏幕开启后onStart再次调用onPause

因此:onCreate - onStart - onResume - onPause - onStop - onStart - onPause

可以通过使用adb命令或eclipse锁定设备并启动活动来验证这一点。

  • 理想解决方案

如果您在onCreate中启动任务,则需要在onDestory中停止该任务(如果任务仍处于待处理状态)。同样地,对于onStart,它将是onStop,对于onResume,它将是onPause

  • 解决方法

如果您无法遵循上述协议,则可以使用onPause方法中的hasWindowFocus检查活动窗口焦点的状态。通常,活动窗口焦点状态在onPause中为真。在屏幕关闭或屏幕显示并显示键盘的情况下,onPause中的活动窗口焦点将为false。

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
    }
}

答案 1 :(得分:1)

android:configChanges="keyboardHidden|orientation|screenSize"中向Activity添加Manifest。这可以解决您的问题。

答案 2 :(得分:1)

你说你想在onStop()中实现一些逻辑但是这样的行为app将无法正常工作。你没有告诉我们你在onStop()中究竟有什么,但我认为你的逻辑可能会重新开始活动..  在这种情况下,您可以在onStop中实现您的逻辑:

@Override
protected void onStop(){
    super.onStop();

         //implement your code only if !STATE_OFF - to prevent infinite loop onResume <-> onStop  while screen is off                      
        DisplayManager dm = (DisplayManager) this.getSystemService(Context.DISPLAY_SERVICE);
        for (Display display : dm.getDisplays()){
               if(display.getState() != Display.STATE_OFF){

                 //implement your code only if device is not in "locked"  state     
                KeyguardManager myKM = (KeyguardManager) this.getSystemService(Context.KEYGUARD_SERVICE);
                if( !myKM.inKeyguardRestrictedInputMode())      
                    //If needed you can call finish() (call onDestroy()) and your logic will restart your activity only once.             
                    finish();                  
                    // implement your logic here (your logic probably restarts the activity)
                }
            }
        }
    }
  1. 其他解决方案可能会帮助你避免onStop()并使用onWindowFocusChanged与bool hasFocus

      /**
      * Called when the current {@link Window} of the activity gains or loses
      * focus.  This is the best indicator of whether this activity is visible
      * to the user.
      */
        @Override
           public void onWindowFocusChanged(boolean hasFocus){
             super.onWindowFocusChanged(hasFocus);
             if( ! hasFocus  ){
             }
             else{
             }
           }
    

答案 3 :(得分:0)

我注意到名为activity的{​​{1}}中有AndroidManifest.xml个属性

例如:

android:showOnLockScreen="true|false"

我在网上搜索了它的文档,但没有运气,但从名称来看,它应该像Window <activity android:name="AlarmAlertFullScreen" android:excludeFromRecents="true" android:theme="@style/AlarmAlertFullScreenTheme" android:showOnLockScreen="true" android:screenOrientation="nosensor" android:configChanges="orientation|screenSize|keyboardHidden|keyboard|navigation"/> 一样工作。


我发现的唯一文件

  

指定应在锁定屏幕上显示活动,并在中   跨所有用户的多用户环境&#39; windows [布尔]


修改

您可以在致电WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED

之前尝试拨打您的国旗代码
super.onCreate(...)

答案 4 :(得分:0)

试试这个。我用过这个并且工作正常

PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);

        _wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
            POWER_SERVICE);
    _wakeLock.acquire();

答案 5 :(得分:-1)

使用WakeLocker类。它有方法唤醒屏幕