【问题标题】:Fragment on Screen Rotation屏幕旋转片段
【发布时间】:2013-10-07 07:46:33
【问题描述】:

我已将一个 viewpager 添加到一个包含两个页面的活动中。

在活动的 onCreate 中,我将片段添加到 fragmentAdapter:

public void onCreate(Bundle savedInstanceState)
{
    ......

    FragmentAdapter fragmentAdapter = new FragmentAdapter
    (
        getSupportFragmentManager(),
        new Fragment[]{FragmentGame.builder(id), FragmentComments.builder(id)},
        new String[]{getString(R.string.gameInfo), getString(R.string.comments)}
    );

    ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
    viewPager.setAdapter(fragmentAdapter);

public static FragmentGame builder(long id)
{
    FragmentGame fragmentGame = new FragmentGame();

    // fragmentGame.id = id;

    Bundle bundle = new Bundle();
    bundle.putLong(Constants.EXTRA_ID, id);
    fragmentGame.setArguments(bundle);

    return fragmentGame;
}

第一次创建活动时,片段的 onCreateView 会按预期调用。

奇怪的行为是当屏幕第一次旋转时,片段的 onCreateView 被调用了两次,但第二次调用只有正确的 id 而第一次调用调用 id 为 0。

在第二个屏幕旋转时,onCreateView 被调用了 3 次,并且再次只有最后一个有 id。

通过更多的屏幕旋转,onCreateView 调用增加。

我发现了一些关于片段和屏幕旋转的相关问题,但我无法弄清楚为什么会发生这种情况以及如何以正确的方式进行。

----- 更新 ------

ID问题解决了,因为我用直接值设置替换了bundle。

【问题讨论】:

    标签: android android-fragments


    【解决方案1】:

    如果您不想在方向更改时重新加载片段,请为您在清单文件中加载片段的活动编写以下内容。

    <activity
                android:name="your activity name"
                android:configChanges="orientation|screenSize" // add this to your activity
                android:label="@string/app_name">
     </activity>
    

    【讨论】:

    • 我知道,但这是唯一发生这种情况的情况吗?
    • 还有另一种方法,即保存您的对象 onSaveInstanceState 并在 onRestoreInstanceState() 方法上检索。为此,您必须在对象上实现 parcelable。
    • 这可能有效,但这是一种“不受欢迎”的方法,因为您正在禁用正常的资源管理和片段生命周期,这让我很痛苦,有这么多人对此表示赞同,因为他们现在可能会导致其他问题为自己。最好一开始就正确地做到这一点,而不是像这样捏造它。例如,如果您有单独的横向布局,则在使用此方法时将永远不会加载这些布局。
    【解决方案2】:

    每次旋转设备时,您都会创建一个新片段并将其添加到 FragmentManager。

    您之前创建的所有片段仍在 FragmentManager 中,因此计数每次增加一。

    如果您希望在片段中保留一个值,则需要将其存储在参数中,否则当系统重新创建片段时,它包含的任何值都会丢失。

    public static FragmentGame builder(long id) {
     Bundle args = new Bundle();
     args.putInt("id", id);
     fragmentGame f = new fragmentGame();
     f.setArguments(args);
    }
    

    我怀疑您确实想在旋转设备时检索先前创建的片段,而不是创建新片段。使用getSupportFragmentManager().findFragmentById()getSupportFragmentManager().findFragmentByTag() 来执行此操作。

    编辑:额外代码

        // Add fragment to the manager
        FragmentTransaction trans=getSupportFragmentManager().beginTransaction();
        trans.add(f,"myTag");
        trans.commit();
    
        // retrieve the fragment
        Fragment f= getSupportFragmentManager().findFragmentByTag("myTag");
    

    尝试检索片段,如果值为 null,则创建一个新片段并将其添加到管理器,否则使用检索到的片段。

    【讨论】:

    • 我用我的问题中的参数替换了直接值设置。我宁愿检索旧片段而不是创建新片段。您能否添加一些有关检索旧片段的代码。我认为 findFragmentById 不适用于 viewPager。如何使用 findFragmentByTag 以及如何为片段添加标签?
    • 片段没有自动添加到fragmentManager?为什么我们将 FragmentManager 传递给 FragmentPagerAdapter?有什么办法可以彻底销毁屏幕旋转时的旧碎片?
    • 某些组件或适配器可能会为您添加它,但通常不会。您可以通过调用 fragmentTransaction 的 remove 方法来删​​除旧片段,但通常您会使用现有片段而不是创建新片段
    • 我想知道配置更改是否是发生这种情况的唯一情况?我的意思是例如暂停或退出应用程序不会导致这种情况?如果这是唯一的情况,那么我更愿意通过修复屏幕旋转来停止它。
    猜你喜欢
    • 2012-01-04
    • 2012-02-20
    • 1970-01-01
    • 2012-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多