Android horizontal and vertical screen conversion problem

Android horizontal and vertical screen conversion problem

Problem Description

  The background is that it is necessary to deploy an APP on the Huawei tablet that can provide relevant Chinese voice prompts and pop-up warnings. The Huawei system is Hongmeng 3.0, which corresponds to Android API 12. After successfully adjusting the first version of the APP, it was found that after the horizontal and vertical screen conversion was performed on the tablet, the Activity would be recreated, and then pop-up windows or voice prompts would cause the APP to exit abnormally. The prompt information is all null pointer or null object class information.

Cause Analysis

  After consulting the data, it is found that when the screen is rotated, the Android system will destroy and recreate the Activity, which is a normal life cycle process. The reason for destroying and recreating the Activity is because a change in screen orientation may cause the layout of the application to change, so the layout needs to be reloaded. However, recreating the Activity will result in the loss of the Activity's state data, such as data entered by the user. In order to solve this problem, Android provides some methods to save and restore the state data of the Activity, such as the Budle object. Specifically, the state data can be saved to the Bundle object in the onSaveInstanceState() method, and then in the onCreate() method. Restoring state data in the Bundle object. as follows:

@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");
        // 恢复状态数据
    }
}

  When the Activity is recreated, both the PopupWindow and the TTS engine need to be reinitialized, otherwise the situation I encountered above may occur.

Solution

  They can be reinitialized in the Activity's onCreate() method, and related resources need to be released in onPause and onDestroy. It should be noted here that it is feasible for the TTS engine to be reinitialized in onCreate, but PopupWindow cannot be initialized in onCreate , the PopupWindow object before destruction will still be used. There is an explanation:
  if you initialize the PopupWindow in the onCreate method, it will be created when the Activity is created. But when the Activity is destroyed, the PopupWindow still exists in the memory and has not been released . When you create the Activity again, the PopupWindow is not recreated, but uses the previous object, but the Activity at this time is no longer the previous Activity, which will cause the PopupWindow to not be correctly bound to the Activity , so it will appear Exception above. Therefore, PopupWindow needs to be recreated in the onResume method , which can ensure that a new PopupWindow object will be created every time the Activity is re-displayed, and correctly bound to the Activity, thereby avoiding the above exception.
  However, even if I recreated the PopupWindow object in onResume, I still encountered “android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?”the same problem. After checking again, I found that the display of PopupWindow depends on a valid Window token, but after the Activity is destroyed and rebuilt, this Window token may become invalid. , resulting in the failure to display the PopupWindow normally, so before trying to display the PopupWindow, it is necessary to judge whether the Window Token is invalid, which can be judged in the onWindowFocusChanged() method, as follows:

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

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

  Problem solved, you're done.

Digression

  In fact, it can also be configured in AndroidManifest.xml, and the Activity will not be automatically destroyed and recreated when the APP is converted from horizontal to vertical, as follows:

android:configChanges="orientation|screenSize|keyboardHidden"

  After this configuration, when the screen orientation, screen size, and keyboard state change, the system will not automatically destroy and recreate the Activity, but call the Activity's onConfigurationChanged() method. In this method, you can handle related logic yourself, such as re-layout and so on. However, this method requires developers to manually handle the changes brought about by configuration changes, which is not convenient for development, and is prone to various strange problems, so I will be lazy and not do the conversion. .

Guess you like

Origin blog.csdn.net/qq_35308053/article/details/130705236