我已经在我的android应用上实现了新的架构组件,但不幸的是,处理这些片段的状态对我来说成了一场噩梦。每当我按下片段的图标时,每次导航时都会重新创建片段。我该如何处理这个问题,或者更确切地说,如何保存这些片段的状态?
下面是我处理这五个片段的主要活动:
public class MainActivityCenterofInformation extends AppCompatActivity {
BottomNavigationView bottomNavigationView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_maincict);
setUpNavigation ();
}
public void setUpNavigation(){
bottomNavigationView = findViewById (R.id.bottom_nav_cict);
NavHostFragment navHostFragment = (NavHostFragment)getSupportFragmentManager ()
.findFragmentById (R.id.nav_host_fragment_cict);
NavigationUI.setupWithNavController (bottomNavigationView, navHostFragment.getNavController ());
}
//adding animations to the fragment
}
我看不懂Kotlin,所以请告诉我Java,谢谢。
3条答案
按热度按时间tf7tbtn21#
**TL;DR:跳至*只需向我演示步骤!!!***部分
这是片段的正常行为。每次删除或替换片段时,都应该重新创建它们,并且应该使用
onSaveInstanceState
恢复它们的状态。这里有一篇很好的文章,描述了如何做到这一点:Saving Fragment States
除此之外,你可以使用View Model,这是下面推荐的android架构的一部分。它们是保留和恢复UI数据的好方法。
您可以通过以下分步代码实验来了解如何实现此体系结构
编辑: 解决方案**
***注意:**该解决方案假定用户不希望使用
ViewModels
,而只是希望使用导航UI隐藏或显示片段 *它包括以下几点
背景:
Android Navigation组件有一个
NavController
类,您可以使用它来导航到不同的目标。NavController
使用一个Navigator
来实际执行导航。Navigator
是一个抽象类,任何人都可以扩展/继承它,以根据目标的类型提供自定义导航。当使用片段作为目的地时,NavHostFragment
使用FragmentNavigator
,其默认实现在我们使用FragmentTransaction.replace()
导航时替换片段,FragmentTransaction.replace()
完全破坏了先前的片段并添加了新片段。因此我们必须创建自己的导航器,而不是使用FragmentTransaction.replace()
,我们将使用FragmentTransaction.hide()
和FragmentTransaction.show()
的组合,以避免碎片被破坏。导航UI的默认行为:
默认情况下,当你导航到除home片段之外的任何其他片段时,它们不会被添加到backstack中,所以假设你按照以下顺序选择片段
您的后栈将只包含
正如您所看到的,片段B、C、D没有添加到backstack,因此按下back press将始终到达片段A,这是主片段
我们现在需要的行为:
我们想要一个简单而有效的行为。我们不想所有的片段都被添加到backstack中,但是如果片段已经在backstack中,我们想把所有的片段都弹出到选定的片段。
假设我按以下顺序选择片段
反栈还应当
在按下返回时,只有最后一个片段应该被弹出,并且backstack应该是这样的
但是如果我们导航到比如说片段B,因为B已经在堆栈中,那么B上面的所有片段都应该被弹出,并且我们的后栈应该看起来像这样
我希望这个行为是有意义的。这个行为很容易使用全局操作来实现,就像你在下面看到的那样,而且比默认的更好。
"好了,帅哥!现在怎么办?"
现在我们有两个选择
1.扩展
FragmentNavigator
1.复制/粘贴
FragmentNavigator
我个人只想扩展
FragmentNavigator
并覆盖navigate()
方法,但由于它的所有成员变量都是私有的,所以我无法实现正确的导航。因此,我决定复制粘贴整个
FragmentNavigator
类,并将整个代码中的名称从 “FragmentNavigator” 更改为我想要的任何名称。只要告诉我步骤就行了!
1.创建自定义导航器
1.使用自定义标记
1.添加全局操作
1.使用全局操作
1.将自定义导航器添加到NavController
步骤1:创建自定义导航器
下面是我的自定义导航器
StickyCustomNavigator
。除了navigate()
方法之外,所有代码都与FragmentNavigator
相同。正如您所看到的,它使用hide()
,show()
和add()
方法,而不是replace()
。逻辑很简单。隐藏上一个片段,显示目标片段。如果这是我们第一次去一个特定的目标片段,那么添加片段,而不是显示它。步骤2:使用自定义标记
现在打开你的
navigation.xml
文件,用你之前在@Navigator.Name()
中给的名字来重命名与底部导航相关的fragment标签。步骤3:添加全局操作
全局操作是一种从应用中的任意位置导航到目标的方法。您可以使用可视编辑器或直接使用xml来添加全局操作。使用以下设置在每个片段上设置全局操作
第一次
这就是添加全局操作后
navigation.xml
的样子步骤4:使用全局操作
当你写
然后在
setupWithNavController()
NavigationUI中使用bottomNavigationView.setOnNavigationItemSelectedListener()
根据被单击的菜单项的id导航到适当的片段。它的默认行为与我前面提到的一样。我们将向它添加我们自己的实现,并使用全局操作来实现我们所需的反按行为。下面是如何在
MainActivity
中简单地执行此操作最后一步5:将您的自定义导航器添加到NavController
在MainActivity中添加导航器,如下所示。确保传递
NavHostFragment
的childFragmentManager
。此外,还使用
setGraph()
方法将导航图添加到此处的NavController
,如下所示。这是我的
MainActivity
在步骤4和步骤5之后的样子希望这对你有帮助。
plupiseo2#
我不完全确定这是否是您正在寻找的答案,但是如果您关心管理状态,管理状态的现代方法是使用称为视图模型的东西。视图模型是MVVM体系结构的一个组件。它们的目的是保存数据并将数据公开给您的片段/活动以显示。使用导航体系结构,如果您将与每个片段相关的数据适当地存储在该视图模型中,则您的状态将被保留在视图模型中。
话虽如此,我个人建议研究一下MVVM体系结构以及视图模型。否则,保留状态的一种蛮力是在整个片段中使用
savedInstance
状态,并手动保存和恢复重要数据。链接:-Android View Model Component-Android architecture guide
44u64gxh3#
我想你可能需要防止在点击底部导航视图项目两次后重新创建片段。
NavigationUI.setupWithNavController (bottomNavigationView, navHostFragment.getNavController ());
之后bottomNavigationView.setOnNavigationItemReselectedListener { /*Nothing to ignore reselection*/}