我有一项活动需要在启动时打开屏幕(如果已关闭)。 所以在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在启动活动后立即调用
所以问题出在启动和继续调用两次,在停止也调用,我想在onStop()中实现一些逻辑,但是,这样的行为app将无法正常工作。
修改
我发现问题只是由于标志FLAG_SHOW_WHEN_LOCKED。当设备被锁定时它只会在活动开始前锁定设备时发生。
P.S我正在使用带有广播接收器的报警管理器,然后从广播接收器开始活动。
答案 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)
}
}
}
}
其他解决方案可能会帮助你避免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类。它有方法唤醒屏幕