Android 多Fragment屏幕旋转的问题

平时写项目的时候会碰到一些需求是涉及到屏幕旋转的,如果旋转屏幕,你的界面布局什么都没改变的话,那就很简单了,但是如果当你屏幕旋转后,需要更改页面布局的话,那就有点麻烦了。
举个简单的例子:
一开始新建一个项目,studio已经自动帮你新建好hello world的代码。运行,然后手机设置可旋转屏幕。
当你旋转屏幕,你看到其实页面没什么变化,还是一样的布局。但是这个显示的Activity却已经变化了。
任何“设置”(Configuration)的改变都可能对Activity的界面造成影响,这时系统会销毁并重建Activity以便反映新的Configuration。 例如orientation,screenSize,字体大小,语言等都是属于configuration,如果你在系统设置里改变了这些,是需要反映到你的app上,那么就会销毁现有的activity,然后重新创建activity显示。该activity先走了onPause,onStop,onDestroy,然后在onCreate。
假设屏幕旋转前,用户正在手机上填写一个注册表单,如果处理不当,用户会发现旋转后的表单变成空白的了,严重影响使用体验。
分两种情况讲:

  1. 如果你的activity只有一种布局(横竖屏都是一样的),那你旋转的话,什么代码都不用写。你的页面还是一模一样的。如果你页面上有EditText,然后输入一些内容,当你旋转后发现这个输入框中还是有你刚刚输入的内容。明明说Activity重新创建了,为什么EditText中还有内容呢?这是因为Google已经考虑到这种情况,对一些基本的控件做了处理,例如EditText,在旋转时会记录该EditText中的内容,当旋转后activity重新创建后,会重新给该EditText赋值。但是不是所有的控件都有这种恢复能力。
    当然如果你界面上还有其他控件的话,没有恢复能力,那你又只有一种布局的话,其实只要设置旋转对其activity无影响就好了。那就是在manifest中给该activity设置android:configChanges="orientation|screenSize|keyboardHidden"
    orientation,屏幕界面旋转(可能是用户手动旋转的),【注意:如果你的开发API等级等于或高于13,你还需要设置screenSize,因为screenSize会在屏幕旋转时改变】。keyboardHidden,键盘辅助功能改变。
    注意,如果你给activity设置了这个,那么当你旋转的时候,就算你布局有横竖屏两种,他也不会变了。这时候他显示的布局取决于一开始你打开这个app时的布局。比如说当你打开app的时候,手机横屏,那么加载出来的布局为横屏布局,当你再旋转到竖屏的话,布局还是显示为横屏。那如果你打开app的时候,手机竖屏,app首先加载出来的布局是竖屏,当你再旋转到横屏的话,还是显示竖屏。这主要是因为你设置了那个configChanges,设置那个的意思就是当这些configuration发生的时候并不销毁activity,而是沿用原来的。
    所以这时候oncreate和ondestroy这些声明周期都不会触发了,但是会触发onConfigurationChanged方法。
    如果你需要在横竖屏旋转时,处理一些事情的话,可以在这个函数中处理,例如弹个toast什么的,看你自己的需求。
  2. 如果你的activity有两种布局,分为横竖屏,那么你的layout就有两个了。
    横屏布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="landscape" />

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
LinearLayout>

竖屏:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="portrait" />

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
LinearLayout>

主要就是改了linearlayout的方向。
当你在运行的时候,你会发现在竖屏时在输入框输入内容,旋转至横屏的时候,输入框的内容没了,这是为什么呢?虽然说光看布局文件代码,几乎都是一样的,但是为什么会这样呢?因为你使用了两个布局文件,两个输入框看似一样,但在android这里理解却不一定是一样,虽然都是同样的输入框,但是意义可能是不一样的,可能在竖屏这个是输入名字,在横屏是输入性别的。那如何做到输入框内容保留呢?那就是给这两个输入框都加上id,并且两个输入框的id需要一样,那么android就会理解为这两个是一样输入框。

现在来讲讲当activity上显示多个fragment当遇到屏幕旋转怎么办?
比如你的屏幕上有4个fragment,分别为abcd,按照顺序显示a->b->c->d,那么当现在显示c的时候,屏幕旋转了,按理来讲应该是显示c,但是却显示了a,这是因为你的activity未设置configChanges,导致屏幕旋转重新创建activity,那么按你代码显示的话,当然是显示第一个了。那如何做到显示c呢,你可以给你的activity设置configChanges,这样就可以了。但是如果你的activity屏幕旋转时,界面的确需要变化,需要显示横屏布局呢?那设置configChanges当然不行了。那你可以旋转前先记录当前显示哪个fragment,当重新创建完毕后,可以再显式调用去显示那个fragment。

我项目的需求是,activity没有横竖屏布局,activity上面显示的fragment们只有一个fragment是有横竖屏的,记那个有横竖屏的fragment为a。而其他的fragment旋转时不需要变,所以我的做法是给该activity设置configChanges,这样可以保证Activity不会重新创建,其他fragment旋转的时候也不会出错,那a怎么办呢?如果只是单纯设置configChanges的话,刚刚说了会显示第一个fragment,可能不是a。
那我的做法是监听activity的onConfigurationChanged这个函数,在这个里面去判断当前显示的fragment是不是a,如果是a则先dismiss掉,然后在重新显示这个fragment,因为再显示的时候,页面已经为横屏,该fragment是会自己选择正确的布局文件的。那么就完成了我的需求,看代码:

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        List frags = getSupportFragmentManager().getFragments();
        Fragment frag;
        for (int i = 0; frags != null && frags.size() > i; i++) {
            frag = frags.get(i);
            if (frag!=null && frag instanceof AFragment) {
                ((AFragment) frag).dismissAllowingStateLoss();
                AFragment temp = new Afragment();
                temp.show(getSupportFragmentManager(),"afragment");
            }
        }
    }

完美解决

你可能感兴趣的:(android)