我有一个Activity
应用程序,其中有多个Fragments
,这些应用程序通过使用导航组件进行切换。当我在两个片段之间切换时,它们的onCreate()
和onDestroy()
方法似乎重叠。因此,当片段访问相同的全局对象时,我很难为它们编写初始化和清理代码。
从Framgent_A
导航到Fragment_B
的方法具有以下顺序:
Fragment_B.onCreate()
Fragment_A.onDestroy()
在Fragment_A.onDestroy()
中,我颠倒了在Fragment_A.onCreate()
中所做的操作。在Fragment_B
中,我期望当onCreate()
被调用时,事物处于中立状态。但是,由于Fragment_A.onDestroy()
尚未被调用,所以不是这种情况。
Android上的重叠是正常的还是在导航组件中配置了错误的内容?有没有其他方法可以实现我要完成的任务?我知道我可以同时使用Fragments
和使其运作,但是我不希望Fragment彼此了解。在我看来,Framgnet_A
在创建Fragment_B
时仍然有效,当Fragment_B
应该替换Fragment_A
时仍然如此。
任何帮助将不胜感激!
修改:
在调试过程中遍历源代码后,我发现在FragmentNavigator.navigate()
FragmentTransaction.setReorderingAllowed()中被调用,这允许对操作进行重新排序,甚至允许onCreate()
调用新片段在上一个onDestroy()
之前。问题仍然存在,如何解决在初始化下一个Fragment中的相同全局状态之前正确清理一个Fragment中的全局状态的问题。
答案 0 :(得分:2)
由于您具有控制片段膨胀的活动,因此您可以手动控制要膨胀的片段的生命周期。通过调用以下方法,您可以控制准备使用全局数据的片段。在这一点上,您将需要一些如何将数据传递回Mainactivity来确定哪个片段处于活动状态,因为您询问如何同时增加两个将共享一个对象的片段。更好的方法是让MainActivity实现具有特定类的FragmentA和FragmentB-detail来执行Stuff这样的工作,您必须像对待Tablet一样对待您的应用并确定2窗格模式,这时您可以在由您控制的那些片段中使用适当的类活动。随附的link matches what your trying to accomplish
private void addCenterFragments(Fragment fragment) {
try {
removeActiveCenterFragments();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.content_fragment, fragment);
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
activeCenterFragments.add(fragment);
fragmentTransaction.commit();
}catch (Exception e){
Crashlytics.logException(e);
}
}
private void removeActiveCenterFragments() {
if (activeCenterFragments.size() > 0) {
fragmentTransaction = fragmentManager.beginTransaction();
for (Fragment activeFragment : activeCenterFragments) {
fragmentTransaction.remove(activeFragment);
}
activeCenterFragments.clear();
fragmentTransaction.commit();
}
}
答案 1 :(得分:2)
Android Fragment
生命周期并不是真正适合您需要的回调主机。导航控制器将用动画替换这两个片段,因此两者在某种程度上都是可见的,并且甚至在进入片段的onPause()
之后,甚至调用了离开片段的onResume()
。
OnDestinationChangedListener
onDestinationChanged()
回调在任何生命周期事件之前被调用。作为一种非常简化的方法(注意泄漏),您可以执行以下操作:
findNavController().addOnDestinationChangedListener { _, destination, _ ->
if(shouldCleanupFor(destination)) cleanup()
}
与其使用单个导航点来更改全局状态,不如使用单个事实点。这可能是与导航层次结构无关的另一个片段。然后,它会像以前一样观察导航:
findNavController(R.id.nav_graph).addOnDestinationChangedListener { _, destination, _ ->
resetAll()
when(distination.id) {
R.id.fragment_a -> prepareForA()
R.id.fragment_b -> prepareForB()
else -> prepareDefault()
}
}
另一个优点是,您也可以等量实现状态更改。
答案 2 :(得分:2)
也许您可以将一些与初始化相关的代码移到假定为onStart()
或onCreateView()
方法片段的中立状态。根据{{3}},这是应该进行初始化的地方。
另一个可用的选项是使用the developer documentation / Observer模式,您可以在片段A中的onDestroy()
完成后通知您的活动。然后,Activity会通知Fragment B,可以安全地采取清理状态并开始初始化。
答案 3 :(得分:0)
我的情况有些不同,如果有人遇到相同的问题,我想分享一下。
我想在当前片段的onPause()
中执行一个操作,但是当一个人从一个片段导航到另一个片段时,我不想执行该代码。我要做的是调用isRemoving()
方法来检查当前片段是否被删除。调用NavController.navigate(...)
方法时将其设置为true。
override fun onPause() {
super.onPause()
if (!isRemoving()) {
// Write your code here
}
}
根据Google的Fragment.isRemoving()
文档:
如果当前正在从其活动中删除此片段,则返回true。这不是它的活动是否结束,而是它是否正在从活动中删除。