3 回答
TA贡献1799条经验 获得超9个赞
如果从后堆栈返回片段,它不会重新创建片段,而是会重新使用同一实例,并从onCreateView()片段生命周期开始,请参见片段生命周期。
因此,如果要存储状态,则应使用实例变量而不要依赖onSaveInstanceState()。
TA贡献1780条经验 获得超4个赞
与Apple UINavigationController和相比UIViewController,Google在Android软件架构方面做得不好。与Android有关的文档Fragment并没有太大帮助。
当您从FragmentA输入FragmentB时,现有的FragmentA实例不会被破坏。当您在FragmentB中按Back返回到FragmentA时,我们不会创建新的FragmentA实例。现有的FragmentA实例onCreateView()将被调用。
关键是我们不应该在FragmentA的视图中再次扩大视图onCreateView(),因为我们使用的是现有FragmentA的实例。我们需要保存并重用rootView。
以下代码运行良好。它不仅保持片段状态,还减少了RAM和CPU负载(因为我们仅在必要时膨胀布局)。我不能相信谷歌的示例代码和文档别说但总是夸大布局。
版本1(请勿使用版本1。请使用版本2)
public class FragmentA extends Fragment {
View _rootView;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (_rootView == null) {
// Inflate the layout for this fragment
_rootView = inflater.inflate(R.layout.fragment_a, container, false);
// Find and setup subviews
_listView = (ListView)_rootView.findViewById(R.id.listView);
...
} else {
// Do not inflate the layout again.
// The returned View of onCreateView will be added into the fragment.
// However it is not allowed to be added twice even if the parent is same.
// So we must remove _rootView from the existing parent view group
// (it will be added back).
((ViewGroup)_rootView.getParent()).removeView(_rootView);
}
return _rootView;
}
}
正如评论所提到的,有时在中_rootView.getParent()为null onCreateView会导致崩溃。第2版按照dell116建议删除了onDestroyView()中的_rootView。已在Android 4.0.3、4.4.4、5.1.0上测试。
版本2
public class FragmentA extends Fragment {
View _rootView;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (_rootView == null) {
// Inflate the layout for this fragment
_rootView = inflater.inflate(R.layout.fragment_a, container, false);
// Find and setup subviews
_listView = (ListView)_rootView.findViewById(R.id.listView);
...
} else {
// Do not inflate the layout again.
// The returned View of onCreateView will be added into the fragment.
// However it is not allowed to be added twice even if the parent is same.
// So we must remove _rootView from the existing parent view group
// in onDestroyView() (it will be added back).
}
return _rootView;
}
@Override
public void onDestroyView() {
if (_rootView.getParent() != null) {
((ViewGroup)_rootView.getParent()).removeView(_rootView);
}
super.onDestroyView();
}
}
警告!!!
这是哈克!虽然我在我的应用程序中使用它,但是您需要仔细测试和阅读评论。
TA贡献1884条经验 获得超4个赞
我猜想有另一种方法可以实现您想要的。我没有说这是一个完整的解决方案,但在我的情况下达到了目的。
我所做的是代替了我刚刚添加目标片段的片段。因此,基本上,您将改为使用add()method replace()。
我还做了什么。我隐藏了当前的片段,并将其添加到堆栈中。
因此,它在不破坏其视图的情况下将新片段覆盖在当前片段上。(检查onDestroyView()是否未调用其方法。加上它可以backstate使我恢复片段。
这是代码:
Fragment fragment=new DestinationFragment();
FragmentManager fragmentManager = getFragmentManager();
android.app.FragmentTransaction ft=fragmentManager.beginTransaction();
ft.add(R.id.content_frame, fragment);
ft.hide(SourceFragment.this);
ft.addToBackStack(SourceFragment.class.getName());
ft.commit();
AFAIK系统仅onCreateView()在视图被破坏或未创建时调用。但是这里我们通过不从内存中删除视图来保存视图。因此,它不会创建新视图。
当您从Destination Fragment返回时,它将弹出最后一个FragmentTransaction删除的顶部片段,这将使最上面的(SourceFragment's)视图显示在屏幕上。
评论:正如我所说,这不是一个完整的解决方案,因为它不会删除Source片段的视图,因此比平时占用更多的内存。但还是要达到目的。另外,我们使用完全不同的隐藏视图机制,而不是替换非传统的视图。
因此,这实际上与维护状态无关,而与维护视图有关。
- 3 回答
- 0 关注
- 477 浏览
添加回答
举报