Android - 在 onCreate() 之后调用 onDestroy()

Android - onDestroy() called after onCreate()

我有一个屏保activity运行,一个小动画。当用户触摸屏幕时,他们将移动到我的 MainActivity。为此,我重写了方法 "onUserInteraction()"。如果您不熟悉,对设备屏幕或其按钮的任何物理触摸都会触发此方法。

每次点击屏幕都会成功进入主界面 activity。但是,如果我按下后退按钮或音量按钮,我会得到以下一系列事件。

  1. onCreate()
  2. onResume()
  3. onPause()
  4. onCreate()
  5. onResume()
  6. onWindowFocusChanged()
  7. onStop()
  8. onDestroy()

在 onCreate() 和 onResume() 中,我将布尔值设置为 true。在 onPause() 和 onDestroy() 中,布尔值设置为 false。所以,当最后调用 onDestroy() 时,我遇到了一个主要问题。与此同时,我可以将我的布尔值设置为仅在 onPause() 期间更改,因为每次切换屏幕时都会调用它,但这个问题仍然困扰着我。

在我的 Logcat 中,就在调用 onDestroy() 之前,我看到以下行:

[MainActivity] Surface release

我的清单中的 MainActivity:

<activity
    android:name=".MainActivity"
    android:screenOrientation="sensorLandscape" />

我在阅读(某处)时提供了以上内容,在 onCreate() 中更改请求的方向可能会导致我的问题。但是,我正在添加标志:

protected void onCreate(Bundle savedInstanceState){
    getWindow.addFlags(WindowManager.LayaoutParams.FLAG_TURN_SCREEN_ON);
    getWindow.addFlags(WindowManager.LayaoutParams.FLAG_KEEP_SCREEN_ON);
    setContentView(R.layout.activity_main);

    // other code...
}

我真正觉得有趣的是,当调用 onDestroy() 时我完全没有问题。所有按钮、菜单项、计时器、后台服务均正常工作。除了这个 'destroying' 我的布尔逻辑,以及 'destroying' 我留下的骄傲......实际上没有任何影响。这是一个错误吗?

运行 Android Studio 3.3.2 与 Gradle 4.10.1

在此先感谢您的帮助。

编辑(2019 年 3 月 21 日)

回答布尔逻辑问题:只要用户在应用程序的主屏幕上,即 "MainActivity",我就会在屏幕上显示弹出窗口。我还会跟踪我是否在屏幕保护程序上 activity - 弹出请求会将用户移至主屏幕,然后打开弹出窗口。

在MainActivity.java

onCreate()  - isHomeScreenActive = true;
onPause()   - isHomeScreenActive = false;
onResume()  - isHomeScreenActive = true;
onDestroy() - isHomeScreenActive = false; //Temporarily removed

从 MainActivity 移动到 ScreenSaver 不是问题,但我在这里添加了代码以防万一。

   public void startScreenSaverTimer(){

       // Restarts the timer when method is called.
       // Touch events, onResume(), onCreate() call this
       if(timer != null){
           timer.cancel();
       }

       // Start Timer
       timer = new Timer();
       timer.schedule(new TimerTask(){
           @Override
           public void run(){
               finish();
               Intent ScreenSaver = new Intent(this, ScreenSaver.class);
               ScreenSaver.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                                    Intent.FLAG_ACTIVITY_CLEAR_TOP);
               startActivity(ScreenSaver);
           }
       }, 60000); //Set to 1 minute
   }

应要求,我在日志中添加了 "this"。结果如下:

E/Tracker: onCreate() Boolean Value = true
E/Tracker: onCreate() called from com.x.x.MainActivity@be81228
E/Tracker: onResume() Boolean Value = true
E/Tracker: onResume() called from: com.x.x.MainActivity@be81228
E/Tracker: onPause() Boolean Value = false
E/Tracker: onPause() called from com.x.x.MainActivity@be81228
E/Tracker: onCreate() Boolean Value = true
E/Tracker: onCreate() called from com.x.x.MainActivity@d0faced
E/Tracker: onResume() Boolean Value = true
E/Tracker: onResume() called from: com.x.x.MainActivity@d0faced
E/Tracker: onWindowFocusChanged() called from com.x.x.MainActivity@d0faced
E/Tracker: onStop() called from com.x.x.MainActivity@be81228
E/Tracker: onDestroy() called from: com.x.x.MainActivity@be81228

从上面看,我们好像启动了两次MainActivity。很好的电话@David Wasser。看来我们离解决这个问题又近了一步。

MainActivity@be81228 (started first, gets Destroyed)
MainActivity@d0faced (started second, stays alive)

因为看起来我们要启动 MainActivity 两次,所以我添加了启动 MainActivity 的 ScreenSaver 代码。

@Override
public void onUserInteraction(){
    super.onUserInteraction();

    // Boolean for tracking screensaver
    isScreenSaverActive = false;

    if(animation != null){
        if(animation.isRunning(){
            animation.stop();
        }
    }

    finish();

    Intent i = new Intent(this, MainActivity.class);
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
               Intent.FLAG_ACTIVITY_CLEAR_TOP);
    startActivity(i)

    Log.e("Tracker", "ScreenSaver onUserInteraction() starting MainActivity);
}

我刚刚添加的上述功能中的日志为我们提供了一个有用的提示:

E/Tracker: ScreenSaver onUserInteraction starting MainActivity
E/Tracker: ScreenSaver onUserInteraction starting MainActivity
E/Tracker: onCreate() Boolean Value = true
E/Tracker: onCreate() called from com.x.x.MainActivity@bcb1a2c
E/Tracker: onResume() Boolean Value = true
E/Tracker: onResume() called from: com.x.x.MainActivity@bcb1a2c
E/Tracker: onPause() Boolean Value = false
E/Tracker: onPause() called from com.x.x.MainActivity@bcb1a2c
E/Tracker: onCreate() Boolean Value = true
E/Tracker: onCreate() called from com.x.x.MainActivity@6ad37bf
E/Tracker: onResume() Boolean Value = true
E/Tracker: onResume() called from: com.x.x.MainActivity@6ad37bf
E/Tracker: onWindowFocusChanged() called from com.x.x.MainActivity@6ad37bf
E/Tracker: onStop() called from com.x.x.MainActivity@bcb1a2c
E/Tracker: onDestroy() called from: com.x.x.MainActivity@bcb1a2c

看起来 onUserInteraction() 对 KeyEvent 响应了两次。可能是 onKeyDown() 和 onKeyUp()。所以,当然我也记录了这个:

E/Tracker: ScreenSaver onUserInteraction starting MainActivity
E/Tracker: ScreenSaver onKeyDown() BACK BUTTON
E/Tracker: ScreenSaver onUserInteraction starting MainActivity
E/Tracker: ScreenSaver onKeyUp() BACK BUTTON
// Same as above for the remainder of logs

看起来 KeyDown/KeyUp 一定是问题所在 - 后退按钮、音量按钮......可能还有卡片视图、bixby 和主页按钮,我什至没想过要测试它们。

目前,我做了一个简单的解决方法,并且有效。但是,我觉得应该有一个更优雅的方法。欢迎任何想法。

private boolean runOnce = false;

@Override
public void onUserInteraction(){

    if(!runOnce){

       runOnce = true;
        // Start MainActivity

    }
}

所以,我想这个故事的寓意是,同时启动相同的 activity 两次,可以导致 onDestroy() 在 "surviving" 克隆 activity 具有被创建。我注意到它的唯一原因是因为我的布尔值更新实际上是在单例 class 中更新静态变量,用于后台服务和其他一些 classes 中的弹出管理。否则,它可能会被忽视。

编辑(2019 年 3 月 22 日)

Android MainActivity 的清单

    <activity
        android:name=".MainActivity"
        android:screenOrientation="sensorLandscape" />

屏幕保护程序Class、onUserInteraction()

@Override
public void onUserInteraction(){
    super.onUserInteraction();

    if(!runOnce){

        runOnce = true;

        SingletonScreenSaverTracker.isScreenSaverActive = false;

        if(animation != null){

            if(animation.isRunning()){
                animation.stop();
            }

        }

        finish();

        Intent i = new Intent(this, MainActivity.class);
        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK   |
                Intent.FLAG_ACTIVITY_CLEAR_TOP);

        startActivity(i);
    }
}

如果不小心使用函数 onUserInteraction() 可能会导致一些问题。在 KeyDown 和 KeyUp 事件期间,按下按钮实际上会触发该方法两次。如果使用此方法启动activity,则点击屏幕即可。但是,按一个键将调用该方法两次,同时尝试启动 activity 两次。

当两个活动同时启动时,android 识别出这一点并杀死其中一个克隆体。如日志所示,第一个实例已被清除,但直到第二个实例已完全创建并具有 window 焦点之后。因此,在 onCreate().

之后,我能够看到在我启动的 activity 上调用了 onDestroy()