Android-фрагмент - Как сохранить состояния представлений во фрагменте, когда поверх него помещается другой фрагмент
Автор вопроса: pankajagarwalОтветов: 11
В Android фрагмент (скажем, FragA) добавляется в стопку, а другой фрагмент (скажем, FragB) появляется наверху. Теперь при ответном ударе FragA выходит наверх, и вызывается onCreateView(). Теперь у меня было FragA в определенном состоянии, прежде чем FragB было нажато поверх него.
Мой вопрос: как я могу восстановить FragA в прежнее состояние? Есть ли способ сохранить состояние (например, в пакете), и если да, то какой метод я должен переопределить?
@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);
}
}
Я новичок в фрагментах, но это похоже на решение вашей проблемы;) OnActivityCreated вызывается после возврата фрагмента из заднего стека.
Ответ 2 · рейтинг 85 · Fyodor Volchyok
Фрагмент onSaveInstanceState(Bundle outState) никогда не будет вызываться, если только активность фрагмента не вызовет его для себя и прикрепленных фрагментов. Таким образом, этот метод не будет вызываться до тех пор, пока что-то (обычно вращение) не заставит активность SaveInstanceState и не восстановить ее позже. Но если у вас есть только одна активность и большой набор фрагментов внутри нее (с интенсивным использованием replace) и приложение работает только в одной ориентации, активность 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);
}
}
Второй, но менее педантичный способ - держать переменные в синглтонах
Третье - не replace() фрагментов, а add()/show()/hide() их.
Ответ 3 · рейтинг 20 · e_v_e
Просто обратите внимание, что если вы работаете с фрагментами с помощью ViewPager, это довольно просто. Вам нужно только вызвать этот метод: setOffscreenPageLimit().
Согласно документам:
Установите количество страниц, которые должны сохраняться по обе стороны от текущей страницы в иерархии представлений в состоянии простоя. Страницы за пределами этого ограничения будут воссозданы с адаптера при необходимости.
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;
}
}
Ответ 5 · рейтинг 8 · rmirabelle
Я работал с проблемой, очень похожей на эту. Поскольку я знал, что мне часто придется возвращаться к предыдущему фрагменту, я проверил, верен ли фрагмент .isAdded(), и если да, то вместо transaction.replace() я просто делаю transaction.show(). Это предотвращает повторное создание фрагмента, если он уже находится в стеке - сохранение состояния не требуется.
Еще одна вещь, которую следует иметь в виду, заключается в том, что, хотя это сохраняет естественный порядок самих фрагментов, вам все же может потребоваться обрабатывать само действие, которое уничтожается и воссоздается при изменении ориентации (конфигурации). Чтобы обойти это в AndroidManifest.xml для вашего узла:
android:configChanges="orientation|screenSize"
В Android 3.0 и выше, по-видимому, требуется screenSize.
Удачи
Ответ 6 · рейтинг 5 · Aman Goel
Лучшее решение, которое я нашел, приведено ниже:
onSavedInstanceState(): всегда вызывается внутри фрагмента, когда активность собирается закрыть (переместить активность из одной в другую или изменить конфигурацию). Итак, если мы вызываем несколько фрагментов для одной и той же активности, мы должны использовать следующий подход:
Используйте OnDestroyView() фрагмента и сохраните весь объект внутри этого метода. Затем OnActivityCreated(): проверьте, является ли объект нулевым или нет (поскольку этот метод вызывается каждый раз). Теперь восстановите состояние объекта здесь.
Всегда работает!
Ответ 7 · рейтинг 4 · Brook Oldre
если вы обрабатываете изменения конфигурации в своей активности фрагмента, указанной в манифесте Android, как это
тогда onSaveInstanceState фрагмента не будет вызываться, а объект savedInstanceState всегда будет нулевым.
Ответ 8 · рейтинг 1 · smallfatter
я не думаю, что onSaveInstanceState это хорошее решение. он просто используется для деятельности, которая была уничтожена.
Начиная с Android 3.0 Fragmen управляется FragmentManager, условие таково: одно действие, отображающее множество фрагментов, когда фрагмент добавляется (не заменяется: он будет воссоздан) в backStack, представление будет уничтожено. когда вернетесь к последнему, он будет отображаться как раньше.
Поэтому я думаю, что fragmentManger и транзакция достаточно хороши, чтобы справиться с этим.
Ответ 9 · Javad
Я использовал гибридный подход для фрагментов, содержащих представление списка. Это кажется эффективным, поскольку я не заменяю текущий фрагмент, а добавляю новый фрагмент и скрываю текущий. У меня есть следующий метод в действии, в котором размещены мои фрагменты:
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();
}
Я использую этот метод в своем фрагменте (содержащем представление списка) всякий раз, когда элемент списка щелкается/нажимается (и поэтому мне нужно запустить/отобразить фрагмент сведений):
getFragmentTags() возвращает массив строк, которые я использую в качестве тегов для разных фрагментов при добавлении нового фрагмента (см. метод transaction.add в методе 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);
}
Ответ 10 · VMMF
В конце концов, после того, как я попробовал многие из этих сложных решений, поскольку мне нужно было только сохранить/восстановить одно значение в моем фрагменте (содержимое EditText), и хотя это может быть не самое элегантное решение, создание SharedPreference и сохранение моего состояния у меня сработало
Ответ 11 · Sreejesh K Nair
Простой способ хранения значений полей в разных фрагментах активности.
Создайте экземпляры фрагментов и добавьте вместо замены и удаления
FragA fa= new FragA();
FragB fb= new FragB();
FragC fc= new FragB();
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragmnt_container, fa);
fragmentTransaction.add(R.id.fragmnt_container, fb);
fragmentTransaction.add(R.id.fragmnt_container, fc);
fragmentTransaction.show(fa);
fragmentTransaction.hide(fb);
fragmentTransaction.hide(fc);
fragmentTransaction.commit();
Затем просто покажите и скройте фрагменты вместо того, чтобы снова добавлять и удалять их.