可以更新片段而不是创建新实例吗?
Posted
技术标签:
【中文标题】可以更新片段而不是创建新实例吗?【英文标题】:Ok to update fragments instead of creating new instances? 【发布时间】:2012-02-22 02:51:48 【问题描述】:在 android 文档中关于使用片段的example 中,当应用程序处于“双视图”模式时,只要应用程序需要显示不同标题的详细信息,就会重新创建详细信息片段。 FragmentTransaction.replace()
用于将每个旧的详细信息片段实例替换为新的。
这是推荐的做法吗?当真正的意图(没有双关语)是更新 UI 显示的内容,而不是 UI 本身时,创建一个新的 UI 实例不是很浪费。在我看来,创建新实例的唯一原因是如果打算将它们添加到后台堆栈,以便用户可以追溯步骤。否则,直接更新片段是否安全/可取?
在示例的情况下,它表示类似于DetailsFragment.setShownIndex()
的方法。这将被调用,传入新的标题索引,而不是重新创建DetailsFragment
。
假设我们有一个版本的示例,其中一个活动管理两个片段,但一次只显示一个,根据需要交换每个片段。活动是否可以为每个片段创建一个实例,保留对每个片段的引用,然后根据需要简单地从自身添加或删除这两个实例?
这样做的一个可能的棘手后果是,当标题片段处于resumed
状态(即处于“前景”)时,选择标题将导致在详细信息时调用DetailsFragment.setShownIndex()
片段处于stopped
状态。
好主意?坏主意?
提前致谢。
【问题讨论】:
【参考方案1】:就像你说的,创建新的 Fragment 实例的主要原因是为了便于使用后栈。重用现有的 Fragment 也是非常安全的(使用 FragmentManager.findFragmentById()
或 FragmentManager.findFragmentByTag()
查找它)。有时你需要充分利用像isVisible()
、isRemoving()
等Fragment 方法,这样你就不会在DetailsFragment
是stopped
时非法引用UI 组件。
无论如何,在您提议的具有 2 个片段的单窗格 Activity 中,您的 setShownIndex
方法可以在 DetailsFragment
中设置一个私有字段,该字段在 onCreateView
或 onActivityCreated
中加载。
例如,
DetailsFragment df = getFragmentManager().findFragmentByTag("details");
if (df != null)
df.setShownIndex(getSelectedIndex());
else
df = DetailsFragment.newInstance(getSelectedIndex());
fragmentTransaction.replace(R.id.frame, df, "details").commit();
在这两种情况下,无论 df 是新创建的还是重用的,onCreateView
和 onActivityCreated
都会在 DetailsFragment
添加到容器时被调用。
但是,如果您想要一个后退堆栈,我强烈建议您只创建新实例,否则您只是为DetailsFragment
的内容实现自己的后退堆栈。
【讨论】:
【参考方案2】:我已经尝试了以下代码,它对我有用:
private void replaceFragment(Class fragmentClass, String FRAGMENT_NAME, android.support.v4.app.FragmentManager fragmentManager)
Fragment fragment = null;
String backStateName = fragmentClass.getName(); // nome della classe del Fragment
Log.d("Fragment: ", "Creazione Fragment: "+backStateName);
Boolean fragmentExit = isFragmentInBackstack(fragmentManager, backStateName);
if (fragmentExit) //Il Fragment è presente nello stacback
// Fragment exists, go back to that fragment
//// you can also use POP_BACK_STACK_INCLUSIVE flag, depending on flow
fragmentManager.popBackStackImmediate(fragmentClass.getName(), 0);
else
// se non esiste lo aggiungiamo
try
fragment = (Fragment) fragmentClass.newInstance();
catch (Exception e)
e.printStackTrace();
// Inizializzo la transazione del Fragment
android.support.v4.app.FragmentTransaction ft = fragmentManager.beginTransaction();
ft.setCustomAnimations(
R.anim.fragment_slide_left_enter,
R.anim.fragment_slide_left_exit,
R.anim.fragment_slide_right_enter,
R.anim.fragment_slide_right_exit);
ft.replace(R.id.frameLayout_contentMain, fragment, FRAGMENT_NAME);
ft.addToBackStack(fragmentClass.getName());
ft.commit();
// Recupero il numero di Fragment presenti
Integer nFragment = fragmentManager.getBackStackEntryCount();
Log.d("Fragment: ", "Numero di Fragment: "+nFragment);
要确定 Fragment 是否已经在 StackBack 中,请执行此函数:
public static boolean isFragmentInBackstack(final android.support.v4.app.FragmentManager fragmentManager, final String fragmentTagName)
for (int entry = 0; entry < fragmentManager.getBackStackEntryCount(); entry++)
if (fragmentTagName.equals(fragmentManager.getBackStackEntryAt(entry).getName()))
return true;
return false;
希望能帮到你
【讨论】:
如果你提供英文的 cmets 会更有帮助 对不起。我是意大利人。以上是关于可以更新片段而不是创建新实例吗?的主要内容,如果未能解决你的问题,请参考以下文章