【问题标题】:Fragment is Recreated when orientation change, when not needed当方向改变时,片段被重新创建,当不需要时
【发布时间】:2015-04-22 12:09:45
【问题描述】:

我有一个带有 to 布局的应用程序。 在纵向中,我在屏幕上有一个碎片,在陆地 - 两个。

在我的 Activity 的 OnCreate 中:

frameDetailsFragment = (FrameLayout) findViewById(R.id.detailsFragment);

    if (frameDetailsFragment != null){
        if (EntryPool.getPool(this).getEntries().size() > 0) {
            detailsFragment = DetailsFragment.newInstance(EntryPool.getPool(this).getEntries().get(0));

            getFragmentManager().beginTransaction()
                    .add(R.id.detailsFragment, detailsFragment, DETAILS_FRAGMENT)
                    .commit();
        }
    }

因此,当我们处于纵向时,我们不会创建 DetailsFragment。 在 DetailsFragment 中没有什么有趣的东西,没有 setRetainState,而且我不在 onAtach() 中保存活动。我只是注销生命周期方法。 因此,当我在 portarit 中启动应用程序时,它可以工作(未创建详细信息片段)。然后我旋转 - 详细信息碎片被装箱。 然后我再次旋转 - 我看到了这个:

  04-22 12:06:42.737    2692    2692    I   ANT DetailsFragment :: onDestroy
  04-22 12:06:42.737    2692    2692    I   ANT DetailsFragment :: onDetach
  04-22 12:06:42.761    2692    2692    I   ANT DetailsFragment :: onAttach
  04-22 12:06:42.761    2692    2692    I   ANT DetailsFragment :: onCreate
  04-22 12:06:42.805    2692    2692    D   ANT MainActivity oncretae
  04-22 12:06:42.845    2692    2692    I   ANT DetailsFragment :: onCreateView
  04-22 12:06:42.857    2692    2692    I   ANT DetailsFragment :: onActivityCreated

正如我们所看到的,frag recretaed bu 片段管理器。为什么?请帮帮我,我在这种行为中看不到任何逻辑 - 在执行添加片段事务时我没有写 setRetainInstanse,也没有 addToBackState

【问题讨论】:

    标签: android android-fragments


    【解决方案1】:

    因为您的问题是为什么会发生这种情况,(其他答案是关于如何阻止它):

    发生这种情况是因为 Activity 不知道何时从已保存的实例状态恢复 Fragment,即不再需要该 Fragment。如果在 Activity 恢复视图层次结构后,存在与 Fragment 最初添加到的 id 相同的视图(transaction.add 中的第一个参数),那么它将在轮换更改后重新添加。

    【讨论】:

    • 看起来确实如此。如果有任何设置行为的好方法,我的片段不会保存在 onSaveInstanceState 中并在不需要时重新创建?
    【解决方案2】:

    在清单文件中添加以下代码,您可以在其中声明从中调用片段的活动:

    android:configChanges="keyboardHidden|orientation|screenSize"
    

    【讨论】:

    • 不,这不是解决方案。仅当我 RECREATE 活动时,Android 才会为我的活动(layout-land)增加另一个布局。
    • 我正在为 lanscape 使用不同的布局,我使用上述解决方案来解决这个问题。
    • 所以您以编程方式决定要扩展哪个布局?采用什么活动方式?
    【解决方案3】:

    你应该在你的片段中 setRetainInstancetrue

    public void setRetainInstance (boolean retain)
    

    控制是否在重新创建 Activity 时保留片段实例(例如来自配置更改)。这只能与不在后台堆栈中的片段一起使用。如果设置,则在重新创建活动时片段生命周期将略有不同:

    onDestroy() 不会被调用(但onDetach() 仍然会被调用,因为片段正在与其当前活动分离)。 onCreate(Bundle) 不会被调用,因为片段没有被重新创建。 onAttach(Activity)onActivityCreated(Bundle) 仍将被调用。

    【讨论】:

    • 是的,但即使我不需要它,仍然会以纵向模式重新创建片段(或重新连接,如果 setRetainInstance 为真)。
    【解决方案4】:

    我按照以下方式决定了这个问题 - 在 OnSaveInstance 状态下,我只需使用片段管理器删除片段(如果存在):

       @Override
    protected void onSaveInstanceState(Bundle outState) {
        if (detailsFragment != null) {
            getFragmentManager().beginTransaction()
                    .remove(detailsFragment)
                    .commit();
        }
    
        super.onSaveInstanceState(outState);
    }
    

    在这个钩子的帮助下,只有当它通过 onCreate 中的检查时,该片段才会在 Activity 中再次创建:

       if (frameDetailsFragment != null){
        if (EntryPool.getPool(this).getEntries().size() > 0) {
            detailsFragment = DetailsFragment.newInstance(EntryPool.getPool(this).getEntries().get(0));
    
            getFragmentManager().beginTransaction()
                    .add(R.id.detailsFragment, detailsFragment, DETAILS_FRAGMENT)
                    .commit();
        }
    

    但可以肯定的是,必须有更好的解决方案,强制片段被销毁、分离,并且永远不会重新记录,只有当它会从 onCreate 调用时

    【讨论】:

    猜你喜欢
    • 2020-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多