Android fragment- Cómo guardar estados de vistas en un fragmento cuando otro fragmento es empujado por encima de él

En android, un fragmento (digamos FragA ) se agrega a la backstack y otro fragmento (digamos FragB ) viene a la parte superior. Ahora en golpear detrás FragA viene a la tapa y el onCreateView() se llama. Ahora tenía FragA en un estado particular antes FragB se empujó en la parte superior de la misma.

Mi pregunta es ¿cómo puedo restaurar FragA a su estado anterior? ¿Hay una manera de ahorrar el estado (como decir en un paquete) y si es así entonces qué método debo anular?

En la guía de fragmentos FragmentList ejemplo puede encontrar:

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

Que se puede utilizar más tarde como este:

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

Soy un principiante en Fragmentos pero parece una solución de su problema;) OnActivityCreated se invoca después de que el fragmento vuelve de la pila trasera.

onSaveInstanceState(Bundle outState) del onSaveInstanceState(Bundle outState) nunca se llamará a menos que la actividad del fragmento lo llame a sí mismo y fragmentos adjuntos. Por lo tanto, este método no se llamará hasta que algo (normalmente la rotación) fuerce la actividad a SaveInstanceState y lo restaure más tarde. Pero si sólo tiene una actividad y un conjunto grande de fragmentos en su interior (con un uso intensivo de replace ) y las ejecuciones de aplicación sólo en una actividad de orientación onSaveInstanceState(Bundle outState) no se puede llamar durante mucho tiempo.

Conozco tres soluciones posibles.

El primero:

Use argumentos de fragmentos para contener datos importantes:

 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); } } 

La segunda pero menos pedante manera – mantener variables en singletons

El tercero – no replace() fragmentos, pero add() / show() / hide() su lugar.

Simplemente observe que si trabaja con Fragments usando ViewPager, es bastante fácil. Sólo necesita llamar a este método: setOffscreenPageLimit() .

Accordign a los documentos:

Establezca el número de páginas que deben conservarse en cualquier lado de la página actual en la jerarquía de vistas en un estado inactivo. Las páginas más allá de este límite se recrearán desde el adaptador cuando sea necesario.

Simmilar cuestión aquí

Infle tu vista por una vez.

Ejemplo:

 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; } 

}

He trabajado con un problema muy similar a este. Como sabía que con frecuencia volvería a un fragmento anterior, verifiqué si el fragmento .isAdded() era verdadero, y si es así, en lugar de hacer una transaction.replace() solo hago una transaction.show() . Esto evita que el fragmento se vuelva a crear si ya está en la pila.

 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(); 

Otra cosa a tener en cuenta es que mientras esto preserva el orden natural de los fragmentos en sí, es posible que todavía tenga que manejar la actividad misma que se destruye y se recrea en el cambio de orientación (config). Para evitar esto en AndroidManifest.xml para tu nodo:

 android:configChanges="orientation|screenSize" 

En Android 3.0 y screenSize posteriores, el screenSize es aparentemente necesario.

Buena suerte

La mejor solución que encontré está abajo:

OnSavedInstanceState (): siempre se llama dentro del fragmento cuando la actividad se va a apagar (mover la actividad de uno a otro o configurar cambios). Así que si estamos llamando múltiples fragmentos en la misma actividad entonces tenemos que usar el siguiente enfoque:

Use OnDestroyView () del fragmento y guarde todo el objeto dentro de ese método. Then OnActivityCreated (): Comprueba que si el objeto es nulo o no (Debido a que este método llama cada vez). Ahora restaure el estado de un objeto aquí.

Sus obras siempre!

Si usted está manejando los cambios de configuración en su actividad de fragmentos especificados en android manifiesto como este

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

Entonces el onSaveInstanceState del fragmento no será invocado y el objeto savedInstanceState siempre será nulo.

 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) { } 

Utilicé un enfoque híbrido para fragmentos que contenían una vista de lista. Parece actuante ya que no reemplazo el fragmento actual, sino que añado el nuevo fragmento y oculto el actual. Tengo el siguiente método en la actividad que hospeda mis fragmentos:

 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(); } 

Utilizo este método en mi fragmento (que contiene la vista de lista) cada vez que se hace clic en un elemento de lista / tapped (y, por tanto, necesito iniciar / mostrar el fragmento de detalles):

 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() devuelve una matriz de cadenas que utilizo como etiquetas para diferentes fragmentos cuando agrego un nuevo fragmento (véase método transaction.add en el método addFragment anterior).

En el fragmento que contiene la vista de lista, lo hago en su método 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(); } 

Luego en onCreateView del fragmento (en realidad en un método que se invoca en onCreateView), restauro el estado:

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

No creo que onSaveInstanceState es una buena solución. Sólo se utiliza para la actividad que había sido destoryed.

Desde android 3.0 el Fragmen ha sido manager de FragmentManager, la condición es: una actividad de mapeo de fragmentos manny, cuando se agrega el fragmento (no reemplazar: se recreará) en backStack, la vista será destored. Cuando vuelve al último, se mostrará como antes.

Así que creo que el fragmentManger y la transacción es lo suficientemente bueno para manejarlo.

Al final después de probar muchas de estas complicadas soluciones ya que solo necesitaba guardar / restaurar un solo valor en mi fragmento (el contenido de un EditText), y aunque podría no ser la solución más elegante, crear una SharedPreference y almacenar mi estado Trabajó para mi

  • Android RecyclerView que se encuentra en un fragmento que se encuentra en un ViewPager no vuelve a cargar / refrescar las vistas si se alcanza el setOffscreenPageLimit
  • ¿Vincular el servicio a la actividad o fragmento?
  • La aplicación se bloquea en rotación sin stackTrace
  • Deslizamiento entre fragmentos
  • Actualizar Navegación cajón listview
  • Android fragmentos analógicos en iOS rápida
  • Cómo manejar onContextItemSelected en una actividad de múltiples fragmentos?
  • ViewPager en DialogFragment, IllegalStateException: Fragmento no tiene una vista
  • El método getView () de ArrayAdapter no se recibe
  • ¿Puedo eliminar un fragmento definido en un archivo layout.xml?
  • Android: Fragmento de preferencia con un fragmento de cajón de navegación
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.