我有一项活动需要在启动时打开屏幕(如果是关闭)。
所以在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在启动活动后立即调用
的onCreate
在onStart
的onResume
在onPause
的onStop
在onStart
的onResume
所以问题出在启动和恢复调用两次,在停止也调用,我想在onStop()中实现一些逻辑,但是,这样的行为应用程序将无法正常工作。
编辑
我发现问题只是由于标志FLAG_SHOW_WHEN_LOCKED。当设备被锁定时它只会在活动开始前锁定设备时发生。
P.S我正在使用带有广播接收器的报警管理器,然后从广播接收器开始活动。
令人惊讶的问题,我也有同样的旗帜FLAG_SHOW_WHEN_LOCKED,投了票
我通过在处理程序中使用一点延迟来解决它,它检查onStop
@Override protected void onStop(){super.onStop(); if(isDeviceSleeping){if(System.currentTimeMillis() - startTime <2000){return; }}
这可能是一种方式,但不是正确的解决方案
这个答案救了我:stackoverflow.com/a/14053686/5247630它是关于检测屏幕是否打开
你的工作了吗? 我遇到了同样的麻烦,虽然我使用了唤醒锁并禁用了键盘锁,它显示了键盘并暂停了我的活动
让我们理解为什么生命周期方法被多次调用。
以下是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.
在onResume之后,活动窗口附加到窗口管理器并调用onAttachedtoWindow。如果屏幕打开,活动窗口将获得焦点,并使用true参数调用onWindowFocusChanged。来自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
在报告的问题中,屏幕如果关闭。因此,活动窗口不会获得焦点,这会导致活动的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
}
}
很好的解释,但解决方法不起作用,我宁愿在onWindowFocusChanged中设置一个标志值,然后在窗口聚焦后处理onPause()和onStop()
为什么您的解决方法不使用onWindowFocusChanged?从表面上看,这个事件听起来很完美。
只需添加onRestart也可以在onStop之后调用。如果有人在onStart中执行某些逻辑,只需检查是否重新启动了活动,然后避免在onStart中再次运行逻辑
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()中实现一些逻辑但是这样的行为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{
}
}
在Manifest中将android:configChanges="keyboardHidden|orientation|screenSize"添加到Activity。这可以解决您的问题。
试着没有运气
这将如何解决问题?侦听配置更改只会阻止活动自动处理更改。它与描述的屏幕开/关场景无关
试试这个。我用过这个,它运行正常
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();
不推荐使用PowerManager.FULL_WAKE_LOCK
我注意到AndroidManifest.xml中的Activity属性名为android:showOnLockScreen="true|false"
例如:
android:excludeFromRecents="true"
android:theme="@style/AlarmAlertFullScreenTheme"
android:showOnLockScreen="true"
android:screenOrientation="nosensor"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard|navigation"/>
我在网上搜索了它的文档,但没有运气,但从它的名字来看,它应该像Window标志WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED那样工作。
我发现的唯一文件
Specify that an Activity should be shown over the lock screen and, in
a multiuser environment, across all users' windows [boolean]
编辑
你可以在调用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);
.
.
.
}
}
没有没有成功,有没有具体的主题?
@Haris请检查编辑的答案。
再次相同的结果
我相信这背后的原因,是关键保护屏幕是第一次停止活动,然后活动再次恢复
使用WakeLocker类。它有唤醒屏幕的方法
试过但失败了。很少有方法被贬低