Android:使用支持片段管理器时复制片段
Posted
技术标签:
【中文标题】Android:使用支持片段管理器时复制片段【英文标题】:Android: Duplicating of fragments when using Support Fragment Manager 【发布时间】:2012-01-01 05:50:04 【问题描述】:我对片段有一个非常奇怪的问题。我使用最新的支持库。我也使用与 Google 在其iosCHED project 中使用的类似代码
但我在旋转后重新创建活动时遇到问题。在销毁并再次创建活动后,我调用管理片段事务的方法(在 onStart 方法中)。此行仅调用一次,但会创建片段 TWICE!
这是我的活动方法:
public abstract class SinglePaneActivity extends FragmentActivity
@Override
protected void onStart()
super.onStart();
if(mFragment == null)
mFragment = onCreatePane();
mFragment.setArguments(Utils.intentToFragmentArguments(getIntent()));
Log.w(TAG, "Fragment creation counter = " + createCounter);
createCounter++;
getSupportFragmentManager()
.beginTransaction()
.add(R.id.root_container,mFragment)
.commit();
@Override
protected void onStop()
Log.i(TAG, "onStop");
if(mFragment != null)
getSupportFragmentManager()
.beginTransaction()
.remove(mFragment)
.commit();
mFragment = null;
super.onStop();
还有我的日志:
--Start of application--
11-18 13:26:37.050: I/SinglePaneActivity(19040): onCreate
11-18 13:26:37.050: I/SinglePaneActivity(19040): onStart
11-18 13:26:37.055: W/SinglePaneActivity(19040): replacing fragment, counter = 1
11-18 13:26:37.075: I/MyFragment(19040): onCreate
11-18 13:26:37.110: I/MyFragment(19040): onActivityCreated
--Rotating the device--
11-18 13:26:39.600: I/SinglePaneActivity(19040): onStop
11-18 13:26:39.600: I/SinglePaneActivity(19040): onDestroy
11-18 13:26:39.605: I/MyFragment(19040): onDestroy
11-18 13:26:39.755: I/MyFragment(19040): onCreate
11-18 13:26:39.755: I/SinglePaneActivity(19040): onCreate
11-18 13:26:39.790: I/MyFragment(19040): onActivityCreated
11-18 13:26:39.800: I/SinglePaneActivity(19040): onStart
11-18 13:26:39.800: W/SinglePaneActivity(19040): replacing fragment, counter = 2
11-18 13:26:39.810: I/MyFragment(19040): onCreate
11-18 13:26:39.815: I/MyFragment(19040): onActivityCreated
--Rotating the device back--
11-18 13:36:47.060: I/SinglePaneActivity(19040): onStop
11-18 13:36:47.060: I/SinglePaneActivity(19040): onDestroy
11-18 13:36:47.060: I/MyFragment(19040): onDestroy
11-18 13:36:47.065: I/MyFragment(19040): onDestroy
11-18 13:36:47.130: I/MyFragment(19040): onCreate
11-18 13:36:47.130: I/MyFragment(19040): onCreate
11-18 13:36:47.130: I/SinglePaneActivity(19040): onCreate
11-18 13:36:47.140: I/MyFragment(19040): onActivityCreated
11-18 13:36:47.150: I/MyFragment(19040): onActivityCreated
11-18 13:36:47.150: I/SinglePaneActivity(19040): onStart
11-18 13:36:47.150: W/SinglePaneActivity(19040): replacing fragment, counter = 3
11-18 13:36:47.160: I/MyFragment(19040): onCreate
11-18 13:36:47.160: I/MyFragment(19040): onActivityCreated
--Exiting the app--
11-18 13:36:48.880: I/SinglePaneActivity(19040): onStop
11-18 13:36:48.885: I/SinglePaneActivity(19040): onDestroy
11-18 13:36:48.885: I/MyFragment(19040): onDestroy
11-18 13:36:48.890: I/MyFragment(19040): onDestroy
11-18 13:36:48.890: I/MyFragment(19040): onDestroy
所以每次旋转后碎片的数量都会增加。
旋转后,它会在进入我的 onStart 方法之前恢复片段,并且我的 onStart 方法会在同一个 Frame 布局容器中创建第二个相同的片段。但是它在哪里恢复了第一个片段?我想禁止它。或者我应该改变我的“如果”来测试它是否已经创建?但我不知道如何确定它。看来空测试没用。
我还通过将add()
方法替换为replace()
来做了一些小变通。之后,片段的数量不会增加,并且在创建新片段之前每个片段都被销毁 onStart
方法创建。但这在一些片段中会造成严重的问题,我在他们的 onCreate 方法中启动了一些后台进程......
请帮帮我...我真的不知道该怎么办。非常感谢您的任何建议或想法!
【问题讨论】:
【参考方案1】:好吧,我找到了解决方案。我必须将带有片段管理器的代码从 onStart 移动到 onCreate 并检查 savedInstanceState
的 null
值。好吧,我不知道它是从savedInstanceState
自动保存和恢复的。很高兴知道!
编辑: 并且要做到完全正确,即当 savedInstanceState 不为空时恢复片段,应该有:
if(savedInstanceState == null)
mFragment = onCreatePane();
mFragment.setArguments(Utils.intentToFragmentArguments(getIntent()));
getSupportFragmentManager()
.beginTransaction()
.add(R.id.root_container,mFragment)
.commit();
else
mFragment = getSupportFragmentManager().findFragmentById(R.id.root_container);
【讨论】:
是的!谢谢你。我一直在努力解决同样的问题。在加载我的片段之前检查我的 Activity 中的 null savedInstanceState 就可以了【参考方案2】:我遇到了类似的问题,但我正在从父片段添加子片段并看到重复的子片段。我试图将它添加到父片段的onStart
中,以便我可以访问父视图,这在onCreate
中不可用。因此,我没有将代码移至onCreate
,而是将其移至onActivityCreated
;该方法可以访问父视图,还可以访问savedInstanceState
变量以检查片段是否已自动添加。从活动中添加片段时这不是问题,因为活动的视图在onCreate
中可用。
如果由于某种原因您需要在onStart
或其他savedInstanceState
不可用的地方添加片段,这里有一个替代方案。使用问题中的原始 onStart 代码...
if(mFragment == null)
mFragment = onCreatePane();
mFragment.setArguments(Utils.intentToFragmentArguments(getIntent()));
Log.w(TAG, "Fragment creation counter = " + createCounter);
createCounter++;
getSupportFragmentManager()
.beginTransaction()
.add(R.id.root_container,mFragment)
.commit();
...你可以replace
而不是add
片段:
if(mFragment == null)
mFragment = onCreatePane();
mFragment.setArguments(Utils.intentToFragmentArguments(getIntent()));
Log.w(TAG, "Fragment creation counter = " + createCounter);
createCounter++;
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.root_container,mFragment)
.commit();
如果片段已经自动添加,你的新片段将在视图中替换它。
【讨论】:
【参考方案3】:或者如果您的片段不在回栈中:setRetainInstance(true);
【讨论】:
不鼓励这样做。如果片段包含对活动实例的任何引用;直接或通过视图等成员,这会导致内存泄漏。以上是关于Android:使用支持片段管理器时复制片段的主要内容,如果未能解决你的问题,请参考以下文章