Android的片段 – 如何保存片段中的视图的状态,当另一个片段被推上它的顶部

在android中,一个片段(比如说FragA )被添加到backstack中,另一个片段(比如FragB )到达顶端。 现在打回FragA来到顶部和onCreateView()被调用。 现在我把FragA置于一个特定的状态,然后FragB被推到了最前面。

我的问题是如何将FragA恢复到之前的状态? 有没有一种方法来保存状态(如在一个捆绑说),如果是的话,那么我应该重写哪种方法?

在片段指南 FragmentList的例子中,你可以find:

 @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("curChoice", mCurCheckPosition); } 

你可以在以后使用这个:

 @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (savedInstanceState != null) { // Restore last state for checked position. mCurCheckPosition = savedInstanceState.getInt("curChoice", 0); } } 

我是碎片的初学者,但它似乎是你的问题的解决scheme;)OnActivityCreated从片段返回栈后调用。

片段的onSaveInstanceState(Bundle outState)永远不会被调用,除非片段的活动调用它本身和附加片段。 因此,这个方法将不会被调用,直到某些事件(通常是旋转)将活动强制为SaveInstanceState并稍后恢复。 但是,如果你只有一个活动和大量的片段(大量使用replace ),并且应用程序只能在一个方向上运行,那么activity的onSaveInstanceState(Bundle outState)可能不会被调用很长时间。

我知道三种可能的解决方法。

首先:

使用片段的参数来保存重要的数据:

 public class FragmentA extends Fragment { private static final String PERSISTENT_VARIABLE_BUNDLE_KEY = "persistentVariable"; private EditText persistentVariableEdit; public FragmentA() { setArguments(new Bundle()); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_a, null); persistentVariableEdit = (EditText) view.findViewById(R.id.editText); TextView proofTextView = (TextView) view.findViewById(R.id.textView); Bundle mySavedInstanceState = getArguments(); String persistentVariable = mySavedInstanceState.getString(PERSISTENT_VARIABLE_BUNDLE_KEY); proofTextView.setText(persistentVariable); view.findViewById(R.id.btnPushFragmentB).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { getFragmentManager() .beginTransaction() .replace(R.id.frameLayout, new FragmentB()) .addToBackStack(null) .commit(); } }); return view; } @Override public void onPause() { super.onPause(); String persistentVariable = persistentVariableEdit.getText().toString(); getArguments().putString(PERSISTENT_VARIABLE_BUNDLE_KEY, persistentVariable); } } 

第二个但不那么迂腐的方法 – 把variables保存在单例中

第三 – 不要replace()片段,而是add() / show() / hide()它们。

只要注意,如果你使用ViewPager处理碎片,这很容易。 你只需要调用这个方法: setOffscreenPageLimit()

根据文档调整:

在空闲状态下,将视图层次结构中应保留在当前页面任一侧的页数。 超出此限制的页面将在需要时从适配器重新创build。

Simmilar问题在这里

只是膨胀你的观点一次。

例如:

 public class AFragment extends Fragment { private View mRootView; @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if(mRootView==null){ mRootView = inflater.inflate(R.id.fragment_a, container, false); //...... } return mRootView; } 

}

我处理了一个与此非常相似的问题。 因为我知道我会经常返回到前一个片段,所以我检查了片段.isAdded()是否为true,如果是这样,而不是做一个transaction.replace()我只是做一个transaction.show() 。 如果已经在堆栈上,这将保持片段不被重新创build – 不需要状态保存。

 Fragment target = <my fragment>; FragmentTransaction transaction = getFragmentManager().beginTransaction(); transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); if(target.isAdded()) { transaction.show(target); } else { transaction.addToBackStack(button_id + "stack_item"); transaction.replace(R.id.page_fragment, target); } transaction.commit(); 

另外需要注意的是,虽然这会保留碎片本身的自然顺序,但您仍然可能需要处理被定向(config)更改而被销毁和重新创build的活动。 在AndroidManifest.xml中为你的节点解决这个问题:

 android:configChanges="orientation|screenSize" 

在Android 3.0及更高版本中, screenSize显然是必需的。

祝你好运

我发现的最佳解决scheme如下:

onSavedInstanceState():在活动closures时总是调用内部片段(将活动从一个移动到另一个或configuration更改)。 所以如果我们在相同的活动上调用多个片段,那么我们必须使用以下方法:

使用片段的OnDestroyView()并将整个对象保存在该方法中。 然后OnActivityCreated():检查对象是否为null(因为此方法每次调用)。 现在恢复对象的状态。

它的作品总是!

如果你正在处理Android清单中指定的片段活动中的configuration更改,像这样

 <activity android:name=".courses.posts.EditPostActivity" android:configChanges="keyboardHidden|orientation" android:screenOrientation="unspecified" /> 

那么片段的onSaveInstanceState将不会被调用,并且savedInstanceState对象将始终为空。

 private ViewPager viewPager; viewPager = (ViewPager) findViewById(R.id.pager); mAdapter = new TabsPagerAdapter(getSupportFragmentManager()); viewPager.setAdapter(mAdapter); viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageSelected(int position) { // on changing the page // make respected tab selected actionBar.setSelectedNavigationItem(position); } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } @Override public void onPageScrollStateChanged(int arg0) { } }); } @Override public void onTabReselected(Tab tab, FragmentTransaction ft) { } @Override public void onTabSelected(Tab tab, FragmentTransaction ft) { // on tab selected // show respected fragment view viewPager.setCurrentItem(tab.getPosition()); } @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) { } 

我使用了一个包含列表视图的片段的混合方法。 它似乎是高性能的,因为我不replace当前的片段,而是添加新的片段,并隐藏当前的片段。 在托pipe我的碎片的活动中,我有以下方法:

 public void addFragment(Fragment currentFragment, Fragment targetFragment, String tag) { FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.setCustomAnimations(0,0,0,0); transaction.hide(currentFragment); // use a fragment tag, so that later on we can find the currently displayed fragment transaction.add(R.id.frame_layout, targetFragment, tag) .addToBackStack(tag) .commit(); } 

每当列表项被点击/点击(因此我需要启动/显示细节片段)时,我在我的片段(包含列表视图)中使用此方法:

 FragmentManager fragmentManager = getActivity().getSupportFragmentManager(); SearchFragment currentFragment = (SearchFragment) fragmentManager.findFragmentByTag(getFragmentTags()[0]); DetailsFragment detailsFragment = DetailsFragment.newInstance("some object containing some details"); ((MainActivity) getActivity()).addFragment(currentFragment, detailsFragment, "Details"); 

getFragmentTags()返回一个string数组,当我添加一个新的片段时(见上面的addFragment方法中的addFragment方法),我使用它作为不同片段的标签。

在包含列表视图的片段中,我在onPause()方法中执行此操作:

 @Override public void onPause() { // keep the list view's state in memory ("save" it) // before adding a new fragment or replacing current fragment with a new one ListView lv = (ListView) getActivity().findViewById(R.id.listView); mListViewState = lv.onSaveInstanceState(); super.onPause(); } 

然后在onCreateView的片段(实际上是在onCreateView中调用的方法),我恢复状态:

 // Restore previous state (including selected item index and scroll position) if(mListViewState != null) { Log.d(TAG, "Restoring the listview's state."); lv.onRestoreInstanceState(mListViewState); } 

我不认为onSaveInstanceState是一个很好的解决scheme。 它只是用于已经破坏的活动。

从android 3.0开始,Fragmen已经被FragmentManagerpipe理,条件是:一个活动映射manny片段,当在backStack中添加片段(而不是replace:将被重新创build)时,视图将被注销。 当回到最后一个,它会像以前一样显示。

所以我认为fragmentManger和交易是足够好的来处理它。

最后,在尝试了许多这些复杂的解决scheme之后,我只需要在Fragment(EditText的内容)中保存/恢复单个值,虽然它可能不是最优雅的解决scheme,但创buildSharedPreference并存储我的状态那里为我工作