La referencia del fragmento a la mActividad se convierte en nula después del cambio de orientación. Mantenimiento ineficaz del estado del fragmento

Mi aplicación consta de varios fragmentos. Hasta ahora he tenido referencias a ellos almacenados en un objeto de aplicación personalizado, pero estoy empezando a pensar que estoy haciendo algo mal.

Mis problemas comenzaron cuando me di cuenta de que todas las referencias de mi fragmento a mActivity se convierten en nulos después de un cambio de orientación. Así que cuando llamo a getActivity () después de un cambio de orientación, se arroja una excepción NullPointerException. He comprobado que onAttach () de mi fragmento se llama antes de hacer la llamada a getActivity (), pero todavía devuelve null.

La siguiente es una versión eliminada de mi MainActivity, que es la única actividad en mi aplicación.

public class MainActivity extends BaseActivity implements OnItemClickListener, OnBackStackChangedListener, OnSlidingMenuActionListener { private ListView mSlidingMenuListView; private SlidingMenu mSlidingMenu; private boolean mMenuFragmentVisible; private boolean mContentFragmentVisible; private boolean mQuickAccessFragmentVisible; private FragmentManager mManager; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /* * Boolean variables indicating which of the 3 fragment slots are visible at a given time */ mMenuFragmentVisible = findViewById(R.id.menuFragment) != null; mContentFragmentVisible = findViewById(R.id.contentFragment) != null; mQuickAccessFragmentVisible = findViewById(R.id.quickAccessFragment) != null; if(!savedInstanceState != null) { if(!mMenuFragmentVisible && mContentFragmentVisible) { setupSlidingMenu(true); } else if(mMenuFragmentVisible && mContentFragmentVisible) { setupSlidingMenu(false); } return; } mManager = getSupportFragmentManager(); mManager.addOnBackStackChangedListener(this); final FragmentTransaction ft = mManager.beginTransaction(); ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); if (!mMenuFragmentVisible && mContentFragmentVisible) { /* * Only the content fragment is visible, will enable sliding menu */ setupSlidingMenu(true); onToggle(); ft.replace(R.id.contentFragment, getCustomApplication().getSportsFragment(), SportsFragment.TAG); } else if (mMenuFragmentVisible && mContentFragmentVisible) { setupSlidingMenu(false); /* * Both menu and content fragments are visible */ ft.replace(R.id.menuFragment, getCustomApplication().getMenuFragment(), MenuFragment.TAG); ft.replace(R.id.contentFragment, getCustomApplication().getSportsFragment(), SportsFragment.TAG); } if (mQuickAccessFragmentVisible) { /* * The quick access fragment is visible */ ft.replace(R.id.quickAccessFragment, getCustomApplication().getQuickAccessFragment()); } ft.commit(); } private void setupSlidingMenu(boolean enable) { /* * if enable is true, enable sliding menu, if false * disable it */ } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // launch the fragment that was clicked from the menu } @Override public void onBackPressed() { // Will let the user press the back button when // the sliding menu is open to display the content. if (mSlidingMenu != null && mSlidingMenu.isMenuShowing()) { onShowContent(); } else { super.onBackPressed(); } } @Override public void onBackStackChanged() { /* * Change selected position when the back stack changes */ if(mSlidingMenuListView != null) { mSlidingMenuListView.setItemChecked(getCustomApplication().getSelectedPosition(), true); } } @Override public void onToggle() { if (mSlidingMenu != null) { mSlidingMenu.toggle(); } } @Override public void onShowContent() { if (mSlidingMenu != null) { mSlidingMenu.showContent(); } } } 

La siguiente es una versión eliminada de la CustomApplication. Mis pensamientos detrás de esta implementación fue garantizar sólo una instancia de cada fragmento durante el ciclo de vida de mi aplicación.

 public class CustomApplication extends Application { private Fragment mSsportsFragment; private Fragment mCarsFragment; private Fragment mMusicFragment; private Fragment mMoviesFragment; public Fragment getSportsFragment() { if(mSsportsFragment == null) { mSsportsFragment = new SportsFragment(); } return mSsportsFragment; } public Fragment getCarsFragment() { if(mCarsFragment == null) { mCarsFragment = new CarsFragment(); } return mCarsFragment; } public Fragment getMusicFragment() { if(mMusicFragment == null) { mMusicFragment = new MusicFragment(); } return mMusicFragment; } public Fragment getMoviesFragment() { if(mMoviesFragment == null) { mMoviesFragment = new MoviesFragment(); } return mMoviesFragment; } } 

Estoy muy interesado en consejos sobre cómo implementar mejor los fragmentos múltiples y cómo mantener sus estados. Para su información, mi aplicación consta de más de 15 fragmentos hasta el momento. He hecho algunas investigaciones y parece que FragmentManager.findFragmentByTag () es una buena apuesta, pero no he sido capaz de implementarlo con éxito.

Mi implementación parece funcionar bien, excepto por el hecho de que las referencias de mActivity se convierten en nulas después de los cambios de orientación, lo que me permite creer que puedo tener algunos problemas de pérdida de memoria también.

Si necesita ver más código, por favor hágamelo saber. He evitado a propósito incluir el código de fragmento, ya que creo firmemente que los problemas están relacionados con mis implementaciones de la actividad y la aplicación, pero puedo estar equivocado.

Gracias por tu tiempo.

Mis pensamientos detrás de esta implementación fue garantizar sólo una instancia de cada fragmento durante el ciclo de vida de mi aplicación

Esto es probablemente parte, si no todos, de la fuente de su dificultad.

En un cambio de configuración, Android volverá a crear sus fragmentos utilizando el constructor de argumento cero público para crear una nueva instancia. Por lo tanto, sus fragmentos de alcance global no "garantizarán sólo una instancia de cada fragmento".

Elimine esta clase de Application personalizada. Por favor, permita que los fragmentos sean recreados de forma natural, o si necesitan vivir la vida de una sola actividad, use setRetainInstance(true) . No intente reutilizar fragmentos entre las actividades.

No veo dónde estás usando la referencia a mActivity. Pero no hagas referencia a ella. Siempre use getActivity ya que la Actividad puede ser recreada después del cambio de orientación. Además, no siempre establecer los campos del fragmento por setters o asignando siempre utilizar un paquete y Argumentos

Práctica recomendada para instanciar un nuevo fragmento de Android

También puede usar setRetainInstance (true) para mantener todos los miembros del fragmento durante el cambio de orientación.

Entendiendo el setRetainInstance del fragmento (boolean)

Para resolver este problema tienes que usar el objeto de actividad proporcionado por el método onAttach de fragmento así que cuando cambias el fragmento de orientación se recrea así que onAttach te da la referencia actual

Si no establece setRetainInstance(true) en onCreate … la colección, por ejemplo, List<Object>, Vector<Object> en la clase Application obtendrá null. Asegúrese de establecer setRetainInstance(true) para que setRetainInstance(true) vivos.

puede utilizar onAttach(Context context) para crear una variable de contexto privado en un fragmento como este

  @Override public void onAttach(Context context) { this.context = context; super.onAttach(context); } 

en el cambio de orientación, onAttach le da nueva referencia al contexto, si desea referencia a la actividad, puede encasillarse el contexto de la actividad.

  • Error de Eclipse: MAT
  • Error de Android: java.lang.OutOfMemoryError: tamaño de mapa de bits supera el presupuesto de VM
  • ¿Tiene Android Studio una herramienta de análisis de memoria como MAT en Eclipse?
  • ¿Cuál es la cantidad máxima de RAM que una aplicación puede usar?
  • Cómo utilizar Eclipse Memory Analyzer Tool (MAT) para analizar un hashmap
  • BitmapFactory.decodeResource y inexplicable Fuera de memoria
  • ¿Por qué hay cientos de mapas de bits en la memoria para una aplicación básica para Android?
  • Adb shell dumpsys meminfo - ¿Cuál es el significado de cada celda de su salida?
  • Guardar en tarjeta SD como archivo de texto
  • Android.view.InflateException: Línea # 2 del archivo XML binario: Error al inflar la clase <unknown>
  • Bitmap reciclado con largeHeap habilitado
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.