Android Honeycomb:如何更改FrameLayout中的碎片,而无需重新创建它们?

jel*_*ish 14 android android-fragments android-3.0-honeycomb

是否可以在片段之间切换而无需一直重新创建片段?如果是这样,怎么样?

在文档中,我找到了如何替换Fragments的示例.

// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();

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

// Commit the transaction
transaction.commit();
Run Code Online (Sandbox Code Playgroud)

但我不希望每次需要时都从头开始创建我的碎片.

我还发现了这个 隐藏/显示片段的例子:

// The content view embeds two fragments; now retrieve them and attach
// their "hide" button.
FragmentManager fm = getFragmentManager();
addShowHideListener(R.id.frag1hide, fm.findFragmentById(R.id.fragment1));
addShowHideListener(R.id.frag2hide, fm.findFragmentById(R.id.fragment2));
Run Code Online (Sandbox Code Playgroud)

但是,如何在XML文件外部创建一个带有ID的片段?

我认为这可能与这个问题有关,但没有答案.:/

非常感谢你,水母

编辑:

这就是我现在这样做的方式:

Fragment shown = fragmentManager.findFragmentByTag(shownFragment);

//...

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (shown != null) fragmentTransaction.hide(shown);

//switch statetement for menu selection, just one example:

SettingsFragment set = (SettingsFragment) fragmentManager.findFragmentByTag(SET);
Toast.makeText(this, "Settings:" + set, Toast.LENGTH_LONG).show();
if (set == null)
{
        set = new SettingsFragment();
        fragmentTransaction.add(R.id.framelayout_content, set, SET);
}
else fragmentTransaction.show(set);
shownFragment = SET;
fragmentTransaction.commit();
Run Code Online (Sandbox Code Playgroud)

如果我调出设置,然后调用其他内容,然后返回设置,吐司首先给我"null",然后"设置:SettingsFragment {40ef ..."秒.

但是,如果我替换fragmentTransaction.add(R.id.framelayout_content, set, SET);fragmentTransaction.replace(R.id.framelayout_content, set, SET);我继续获得"null","null","null"...所以它似乎没有找到Fragment by标签.

EDIT2:

添加fragmentTransaction.addToBackStack(null);诀窍.:)这节省了整个隐藏/记忆哪个片段显示的部分,所以我认为这是最优雅的解决方案.

我发现教程对该主题非常有帮助.

EDIT3:

看着我的代码,我意识到我可以摆脱一些部分,所以我把它改成:

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (shown != null) fragmentTransaction.hide(shown);
Settings set = (Settings) fragmentManager.findFragmentByTag(SET);
if (set == null) set = new Settings();

fragmentTransaction.replace(R.id.framelayout_content, set, SET);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Run Code Online (Sandbox Code Playgroud)

然而,这引用了一个IllegalStateException: Fragment already added,就像这里一样.有没有一种简单的方法来防止这种情况?否则我想我可能会切换回隐藏/显示位.

PJL*_*PJL 5

它可能取决于您试图避免重新创建的内容.

// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
Run Code Online (Sandbox Code Playgroud)

在您的示例示例中,当您从newFragment中点击后退按钮时,将显示前一个片段(您将获得onCreateView,onActivityCreated但没有onCreate),因此不会像这样重新创建片段.至于你newFragment,你可以保留它,如果你计划再次使用它更新任何内部状态,如onCreate或onActivityCreated所需.

编辑:

如果你只是有一个菜单列表,每个条目在右窗格中调用一个不同的片段,那么添加到后面的堆栈就不是你想要的了.为此,您可以预先调用add(...)每个片段,然后根据需要隐藏/显示每个片段(我没有对此进行测试).否则我建议保持对每个片段的引用,调用replace(...)选择不同的菜单项,确保不添加到后栈.

  • @jellyfish,请注意[link](http://stackoverflow.com/questions/6250580/fragment-already-added-illegalstateexception),因为有一个错误意味着如果替换片段你不应该使用`replace`以前弹出过.请改用`remove()`和`add()`. (5认同)