android service onstop,关于android:OnPause和OnStop()在启动活动后立即调用

博客讨论了在Android应用中遇到的一个问题,即活动生命周期方法在设备屏幕关闭和解锁时被不期望地多次调用。作者详细分析了问题的根源,涉及到`WindowManager.LayoutParams`的标志,如`FLAG_KEEP_SCREEN_ON`、`FLAG_SHOW_WHEN_LOCKED`和`FLAG_TURN_SCREEN_ON`。他们发现问题与设备锁定和屏幕关闭时活动的启动有关,导致onPause和onStop方法被不正常地调用。解决方案包括在onPause中检查窗口焦点,或者在onWindowFocusChanged中处理逻辑。此外,还提到了其他可能的解决策略,如使用BroadcastReceiver和AlarmManager。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我有一项活动需要在启动时打开屏幕(如果是关闭)。

所以在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类。它有唤醒屏幕的方法

试过但失败了。很少有方法被贬低

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值