横竖屏切换时Activity和Fragment的生命周期问题

最近一段时间在写自己的一个小项目(叫Piebald)时遇到一个恼人的问题:就是横竖屏切换时,Fragment的生命周期函数会重复调用。我这个项目的思路是这样的,在一个Activity布局中有一个Fragment,Fragment的布局是一个RecyclerView, 我想要实现的是:竖屏时RecyclerView,只有一列(即跟ListView 一样),横屏时RecyclerView成两列。实现过程中我发现横竖屏切换时Fragment的onCreate(), onCreateView()等函数会调用两次,这导致初始化进行的一些数据加载操作出现了严重的Bug, 让我特别头大,所以决定探索这其中是怎么回事,所以做了以下测试。

我们知道在Activity布局中放置Fragment有两种方式:1、直接在Activity布局中将Fragment完整类名加入,如<package.MyFragment />;2、在Activity布局中放一个没有子View的FrameLayout,然后在Activity的Java代码中通过getFragmentManager().beginTransaction().replace(R.id.container, MyFragment.class); 动态放入Fragment。这两种情况的测试结果如下:

1、第一种方法

新建了一个MyFragment, 在其生命周期函数中都用Log打印一些信息, 然后在acitivity_main.xml中直接放在根布局下。MainActivity代码中,onCreate()中只有如下语句

super.onCreate(savedInstanceState);
Log.d("LifeCycle", "Activity:onCreate()");
setContentView(R.layout.activity_main);

然后在Activity的其他生命周期函数也用Log打印信息,然后运行程序。Log打印信息如下:

横竖屏切换时Activity和Fragment的生命周期问题_第1张图片

接下来旋转模拟器的屏幕,Log信息如下:

横竖屏切换时Activity和Fragment的生命周期问题_第2张图片

可以看到Activity和Fragment都是先销毁然后再重新初始化,Fragment的初始化方法(红色框里)在这里也调用了一次。


2、第二种方法

acitivity_main.xml代码如下

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    xmlns:android="http://schemas.android.com/apk/res/android" >
    <FrameLayout
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
</LinearLayout>
在onCreate()中加入如下语句

fragment = new MainActivityFragment();
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, fragment)
                .commit();
运行程序,打印信息如下

横竖屏切换时Activity和Fragment的生命周期问题_第3张图片

跟第一种方法没区别

接着旋转屏幕,Log打印信息如下

横竖屏切换时Activity和Fragment的生命周期问题_第4张图片

可以看到Fragment先创建,再销毁,又再创建,框里的方法调用了两次,红色框是第一次调用,蓝色框是第二次调用。
而我的项目正好就是用的第二种方法,于是搜索阅读了很多文章,大致的解决的方法就是在AndroidManifest.xml中相应activity中添加如下属性

android:configChanges="orientation|screenSize"
这样当进行横竖屏切换时,onConfigurationChanged()方法就会被调用, 同时Activity和Fragment也不会再初始化一遍了,我们来测试一下。

在Activity和Fragment都复写了onConfigurationChanged(),只执行了Log打印,然后运行程序,此时打印信息跟上面是完全一样的,接着再来切换为横屏,打印信息如下


可以发现只有Fragment和Activity的onConfigurationChanged()调用了。这样就可以解决使用第二种方法时Fragment初始化方法调用两次的问题了。

不过呢,这在我的项目里问题还是没有解决,上面的解决方法让Fragment在横竖屏切换时一次也不初始化了,但我要实现的是切换成横屏时将Fragment中的RecyclerView切换为两列,这就以为着横竖屏切换时Fragment一定要初始化一次。我的解决方法是在onConfigurationChanged()方法中执行getFragmentManager().beginTransaction().replace()这一系列方法, 这样一来,每次横竖屏切换时Fragment都只会初始化一次了,然后在Fragment的onCreateView()中加入对当前的横竖屏情况进行判断,决定RecyclerView是一列还是两列。至此,我的问题就彻底解决了。

你可能感兴趣的:(生命周期,Activity,Fragment,横竖屏切换)