添加到后台堆栈时,如何维护碎片状态?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (49)

我写了一个在两个片段之间切换的虚拟活动。当你从FragmentA到FragmentB时,FragmentA被添加到后端堆栈中。然而,当我回到FragmentA(通过按回)时,会创建一个全新的FragmentA并且它所处的状态会丢失。

public class FooActivity extends Activity {
  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    final FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(android.R.id.content, new FragmentA());
    transaction.commit();
  }

  public void nextFragment() {
    final FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(android.R.id.content, new FragmentB());
    transaction.addToBackStack(null);
    transaction.commit();
  }

  public static class FragmentA extends Fragment {
    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
      final View main = inflater.inflate(R.layout.main, container, false);
      main.findViewById(R.id.next_fragment_button).setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
          ((FooActivity) getActivity()).nextFragment();
        }
      });
      return main;
    }

    @Override public void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
      // Save some state!
    }
  }

  public static class FragmentB extends Fragment {
    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
      return inflater.inflate(R.layout.b, container, false);
    }
  }
}

添加了一些日志消息:

07-05 14:28:59.722 D/OMG     ( 1260): FooActivity.onCreate
07-05 14:28:59.742 D/OMG     ( 1260): FragmentA.onCreateView
07-05 14:28:59.742 D/OMG     ( 1260): FooActivity.onResume
<Tap Button on FragmentA>
07-05 14:29:12.842 D/OMG     ( 1260): FooActivity.nextFragment
07-05 14:29:12.852 D/OMG     ( 1260): FragmentB.onCreateView
<Tap 'Back'>
07-05 14:29:16.792 D/OMG     ( 1260): FragmentA.onCreateView

它永远不会调用FragmentA.onSaveInstanceState,当你回击时它会创建一个新的FragmentA。但是,如果我在FragmentA上并锁定屏幕,FragmentA.onSaveInstanceState确实会被调用。太奇怪了......我错在期待将一个片段添加到后端堆栈而不需要重新创建?以下是文档的说明:

而如果在删除片段时确实调用了addToBackStack(),则片段将停止,并且如果用户返回,将会恢复。

提问于
用户回答回答于

如果从后端堆栈返回片段,则不会重新创建片段,而是重新使用相同的实例并从onCreateView()片段生命周期开始

所以如果你想存储状态,你应该使用实例变量,而不是依赖onSaveInstanceState()

用户回答回答于

有时_rootView.getParent()是空的onCreateView,这会导致崩溃。按照dell116的建议,版本2删除了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();
    }
}

警告!!!

这是一个HACK!虽然我在我的应用程序中使用它,但您需要仔细测试和阅读注释。

扫码关注云+社区