Android 横竖屏转换问题

Android 横竖屏转换问题

问题描述

  背景是需要在华为平板上部署一个能够进行相关中文语音提示,同时可以进行弹窗预警的APP,华为系统为鸿蒙3.0,对应Android API 12。在成功调通一版APP后,发现在平板上进行横竖屏转换后,Activity会重新创建,此后进行弹窗或语音提示导致APP异常退出。提示信息均为空指针或空对象类信息。

原因分析

  经查阅资料发现,在进行屏幕旋转时,Android系统会销毁并重新创建Activity,这是正常的生命周期过程。销毁和重新创建Activity的原因是因为屏幕方向的改变可能会导致应用程序的布局发生变化,因此需要重新加载布局。但是,重新创建Activity会导致Activity的状态数据丢失,例如用户输入的数据等。为了解决这个问题,Android提供了一些方法来保存和恢复Activity的状态数据,如Budle对象,具体地,可以在onSaveInstanceState()方法中将状态数据保存到Bundle对象中,然后在onCreate()方法中从Bundle对象中恢复状态数据。如下:

@Override
protected void onSaveInstanceState(Bundle outState) {
    
    
    outState.putInt("myInt", 123);
    super.onSaveInstanceState(outState);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
    
    
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (savedInstanceState != null) {
    
    
        int myInt = savedInstanceState.getInt("myInt");
        // 恢复状态数据
    }
}

  当Activity重新创建后,PopupWindow和TTS引擎都需要重新初始化,否则便可能出现我上述遇到的情况。

解决方法

  可以在Activity的onCreate()方法中重新初始化它们,同时需要在onPause和onDestroy中释放相关资源,这里需要注意的是,TTS引擎在onCreate中重新初始化是可行的,但是PopupWindow则无法在onCreate中完成初始化,依然会使用销毁前的PopupWindow对象,有个解释是这样的:
  如果你在onCreate方法中初始化了PopupWindow,那么它是在Activity被创建时就会被创建出来。但是当Activity被销毁后,PopupWindow仍然存在于内存中,并没有被释放掉。当你再次创建Activity时,PopupWindow并没有被重新创建,而是使用之前的对象,但是此时的Activity已经不是之前的Activity了,这会导致PopupWindow无法正确地绑定到Activity上,因此就会出现上述异常。所以需要在onResume方法中重新创建PopupWindow,这样可以保证每次Activity被重新展示时都会创建新的PopupWindow对象,并正确地绑定到Activity上,从而避免了上述异常。
  然而即使我在onResume中重新创建了PopupWindow对象,依然遇到了“android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?”的问题,经再次查阅,发现是因为PopupWindow的显示依赖于一个有效的Window token,但是在Activity被销毁重建后,这个Window token可能会失效,导致无法正常显示PopupWindow,所以在尝试显示PopupWindow之前,还需要判断Window Token是否失效,可以在onWindowFocusChanged()方法中进行判断,如下:

@Override
    public void onWindowFocusChanged(boolean hasFocus) {
    
    
        super.onWindowFocusChanged(hasFocus);

        // 在窗口获得焦点时显示PopupWindow
        if (hasFocus && mPopupWindow != null) {
    
    
            mPopupWindow.showAtLocation(getWindow().getDecorView(), Gravity.CENTER, 0, 0);
        }
    }

  问题解决,大功告成。

题外话

  其实也可以通过在AndroidManifest.xml中配置,当APP横竖屏转换时不会自动销毁并重新创建Activity,如下:

android:configChanges="orientation|screenSize|keyboardHidden"

  这样配置后,当屏幕方向、屏幕大小、键盘状态改变时,系统将不会自动销毁并重新创建Activity,而是调用Activity的 onConfigurationChanged() 方法。在此方法中,可以自己处理相关的逻辑,例如重新布局等等。但是这种方式需要开发者手动处理配置改变带来的变化,不便于开发,也容易出现各种奇怪的问题,我就偷懒不做转换了。。

猜你喜欢

转载自blog.csdn.net/qq_35308053/article/details/130705236