OnPause and OnStop() called immediately after starting activity
我有一项活动需要在启动时打开屏幕(如果是关闭)。
所以在onCreate中,我有:
1 2 3 4 5 6 7 | 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在启动活动后立即调用
所以问题出在启动和恢复调用两次,在停止也调用,我想在onStop()中实现一些逻辑,但是,这样的行为应用程序将无法正常工作。
编辑
我发现问题只是由于标志FLAG_SHOW_WHEN_LOCKED。当设备被锁定时它只会在活动开始前锁定设备时发生。
P.S我正在使用带有广播接收器的报警管理器,然后从广播接收器开始活动。
- 让我们理解为什么生命周期方法被多次调用。
以下是ActivityThread中记录的重要代码注释,它负责执行应用程序进程的活动。
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.
在
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
在报告的问题中,屏幕如果关闭。因此,活动窗口不会获得焦点,这会导致活动的
由于在活动窗口上设置了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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; } ... } |
屏幕打开后,再次调用
因此:
这可以通过使用
- 理想解决方案
如果您在
- 解决方法
如果您不能遵循上述协议,则可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 } } |
Manish Mulimani的解决方法为我工作,除了我首先检查窗口焦点然后调用super.onPause():
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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()中实现一些逻辑但是这样的行为app将无法正常工作。你没有告诉我们你在onStop()中究竟有什么,但我认为你的逻辑可能会重新开始活动..
在这种情况下,您可以在onStop中实现您的逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @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) } } } } |
其他解决方案可能会帮助你避免onStop()并使用onWindowFocusChanged与bool hasFocus
1 2 3 4 5 6 7 8 9 10 11 12 13 | /** * 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{ } } |
在
试试这个。我用过这个,它运行正常
1 2 3 4 5 | 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(); |
我注意到
例如:
1 2 3 4 5 6 | <activity android:name="AlarmAlertFullScreen" android:excludeFromRecents="true" android:theme="@style/AlarmAlertFullScreenTheme" android:showOnLockScreen="true" android:screenOrientation="nosensor" android:configChanges="orientation|screenSize|keyboardHidden|keyboard|navigation"/> |
我在网上搜索了它的文档,但没有运气,但从它的名字来看,它应该像Window标志
我发现的唯一文件
Specify that an Activity should be shown over the lock screen and, in
a multiuser environment, across all users' windows [boolean]
编辑
你可以在调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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); . . . } } |
使用WakeLocker类。它有唤醒屏幕的方法