【问题标题】:issue while switching between views (inflated fragments) in FrameLayout在 FrameLayout 中的视图(膨胀片段)之间切换时出现问题
【发布时间】:2017-02-12 08:09:37
【问题描述】:

我的问题如下:

我有一个应用程序,它有一个主要活动,其中有 是一个 frameLayout 容器 (containerViewId),我用来在菜单导航器选择时显示/膨胀不同的片段。

我实际上做的是在 onCreate() 活动上创建所有片段对象并将其添加到 frameLayout:

伪代码:

// 在主活动中 onCreate()

Fragment1 fragment_1 = new Fragment1();

Fragment2 fragment_2 = new Fragment2()

Fragment3 fragment_3 = new Fragment3()

fragmentTransaction.add(containerViewId, fragment_1, "frag_1");
fragmentTransaction.add(containerViewId, fragment_2, "frag_2");
fragmentTransaction.add(containerViewId, fragment_3, "frag_3");

// hide fragments 2&3, so only fragment_1 is showed

fragmentTransaction.hide(fragment_2);

fragmentTransaction.hide(fragment_3);

.commit()..

现在,当用户从导航视图中选择特定选项时,我只是 隐藏当前显示的fragment,并将需要的fragment显示如下(例如从fragment_1切换到fragment_2):

 fragmentTransaction.hide(fragment_1);

 fragmentTransaction.show(fragment_2);

 fragmentTransaction.commit();

一切都按预期工作(片段已成功切换),但我有时观察到一段时间后(当我将应用程序从后台移到前面时)以前的片段突然显示/重叠在一起(即使我总是隐藏当前片段并显示下一个)

我错过了什么吗? 为什么会突然显示我之前的视图?

谢谢:-)

【问题讨论】:

    标签: android fragment android-framelayout


    【解决方案1】:

    您需要替换而不是堆叠片段。如果您想有可能导航回上一个片段,请使用addToBackStack

    // Replace whatever is in the fragment_container view with this fragment,
    // and add the transaction to the back stack so the user can navigate back
    transaction.replace(R.id.fragment_container, newFragment);
    transaction.addToBackStack(null);
    
    // Commit the transaction
    transaction.commit();
    

    fragmentmanager 上有一些方法可以从 backstack 中获取或弹出先前的 Fragment:popBackStack()、getBackStackEntryAt(int index) 等等。

    更新

    方法popBackStack 弹出backstack 的顶部。后台包含BackStackEntries。 Backstack Entry 仅包含片段的一些参考字段。您应该将片段作为变量保留在包含类中,以便您可以替换它们。请注意,您应该始终实施适当的生命周期管理,因为在 Android 中,如果您在后台拥有数据,您永远无法确定数据是否仍在内存中。

    这里有一些关于 Activity 生命周期的信息,但对于 Fragment 来说基本相同:

    当您的活动在之前被销毁后重新创建时,您 可以从系统传递的Bundle中恢复你保存的状态 你的活动。 onCreate() 和 onRestoreInstanceState() 回调方法接收包含该实例的相同 Bundle 状态信息。

    因为无论系统是否正在创建都会调用onCreate()方法 您的活动的新实例或重新创建以前的活动,您必须 在尝试读取之前检查状态 Bundle 是否为空。 如果为空,则系统正在创建一个新的实例 活动,而不是恢复之前被破坏的活动。

    关于片段生命周期的一些官方文档:https://developer.android.com/guide/components/fragments.html#Lifecycle

    【讨论】:

    • 谢谢。假设我第一次替换 fragment_1 并将其添加到 backstack,现在用户对其相关视图进行了一些更改,然后用户决定切换到 fragment_2,我像以前一样替换它并将其添加到 backstack。此时如果我想导航回fragment_1,我应该怎么做?使用 getBackStackEntryAt(frag1_idx) 获取片段引用并替换它?它会在离开时显示 fragment_1 视图吗?所有用户视图都发生了变化?
    【解决方案2】:

    保持简单。做这样的事情 -

        Fragment1 fragment_1 = new Fragment1();
        Fragment2 fragment_2 = new Fragment2();
        Fragment3 fragment_3 = new Fragment3();
    
        fragmentTransaction.replace(containerViewId, fragment_1, "frag_1"); //when you want show fragment 1
        fragmentTransaction.commit();
    
    //similarly just replace with fragment2 and fragment 3 when you want to show them respectively.The trick is to replace (which internally removes all previously added fragments before adding the current fragment, thus no overlapping issues)
    

    【讨论】:

    • 感谢您的回复。我不能只替换它,因为我需要在用户导航返回时恢复我的最新片段数据。
    • 这是我认为在问题中没有提到或我错过的东西。无论哪种方式,解决方案都是添加行 fragmentTransaction.addToBackStack(null); (线程上的另一个答案已经触及的东西)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多