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

我有一个活动,当它启动时需要打开屏幕(如果已closures)。 所以在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); 

在广播接收机的帮助下使用这个function,我可以使我的活动显示每当它从广播接收机启动。

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

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

所以问题是在开始和简历调用两次,停止也调用,我想在onStop()中实现一些逻辑,但与这样的行为应用程序将无法正常工作。

编辑

我发现问题只是由于标志FLAG_SHOW_WHEN_LOCKED。 当设备被locking时。 只有当设备在活动开始之前被locking时才会发生。

PS我使用广播接收器的报警pipe理器,然后从广播接收器开始活动。

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

下面是一个在ActivityThread中logging的重要代码注释,它负责执行应用程序的活动。

我们通过正常的启动来完成这个任务(因为他们第一次运行onResume()之前,他们的窗口被显示之前他们会经历onResume()),然后暂停它。

onResume之后,将活动窗口附加到窗口pipe理器,并调用onAttachedtoWindow 。 如果屏幕打开,则活动窗口将获得焦点,并使用true参数调用onWindowFocusChanged 。 从文档 :

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

在报告的问题中,屏幕如果closures。 因此活动窗口不会得到焦点,这导致活动的onPause方法被调用,接着是onStop方法,因为活动窗口不可见。

由于在活动窗口上设置了WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON标志,所以窗口pipe理器服务使用电源pipe理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; } ... } 

屏幕打开后, onStartonPause再次被调用。

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

这可以通过locking设备并使用adb命令或eclipse启动活动来validation。

  • 理想解决scheme

如果您在onCreate启动任务,则需要在onDestory停止它(如果任务仍未完成)。 同样onStart它将onStoponResume它将onPause

  • 解决方法

如果你不能遵循上面的协议,你可以在onPause方法中使用hasWindowFocus检查活动窗口焦点的状态。 通常,在onPause ,活动窗口焦点状态将为true。 在屏幕closures或显示键盘锁的情况下,在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 } } 

在您的Manifest为您添加android:configChanges="keyboardHidden|orientation|screenSize" 。 这可能会解决你的问题。

我注意到在AndroidManifest.xmlactivity属性,名为android:showOnLockScreen="true|false"

例如:

  <activity android:name="AlarmAlertFullScreen" android:excludeFromRecents="true" android:theme="@style/AlarmAlertFullScreenTheme" android:showOnLockScreen="true" android:screenOrientation="nosensor" android:configChanges="orientation|screenSize|keyboardHidden|keyboard|navigation"/> 

我搜查了网页的文档,但没有运气,但从它的名字,它应该作为窗口标志WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED做。


我find的唯一文档

指定应该在locking屏幕上显示一个活动,并在多用户环境中跨所有用户的窗口显示[布尔]


编辑

在调用super.onCreate(...)之前,您可以请尝试调用您的标志代码super.onCreate(...)

 public class BaseActivity extends Activity { @Override protected void onCreate(Bundle bundle) { 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); //then call super super.onCreate(bundle); . . . } } 

尝试这个。 我用这个,它工作正常

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

Manish Mulimani的解决方法为我工作,除了我首先检查窗口焦点,然后调用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 } } 

你说你想在onStop()中实现一些逻辑,但这样的行为应用程序将无法正常工作。 你没有向我们展示你在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. 其他的解决scheme,可能会帮助你将避免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{ } } 

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