¿Por qué no Fragment retener el estado cuando se gira la pantalla?
He tenido problemas para obtener algunas subclases de DialogPreference personalizadas dentro de un PreferenceFragment para permanecer visibles cuando se gira la pantalla. No experimento este problema al usar una PreferenceActivity, por lo que no sé si se trata de un error de Android o un problema con mi código, pero me gustaría que alguien confirme si están teniendo la misma experiencia.
Para probar esto, primero cree una pantalla de preferencias que contenga al menos un DialogPreference (no importa qué subclase). Luego muéstrelo en una PreferenciaActividad. Cuando ejecute su aplicación, presione en DialogPreference para que aparezca el cuadro de diálogo. A continuación, gire la pantalla para cambiar la orientación. ¿Permanece visible el cuadro de diálogo?
- Preferencia en el oyente de cambio
- Pantalla de Preferencias de Android sin XML
- Fragmento abierto del fragmento Preferencia; Cambiar el diseño de la barra de acción desde la pantalla de Preferencias anidadas en Android
- SetDisplayHomeAsUpEnabled () no funciona en PreferenceActivity
- Android: No se puede encontrar la clase de actividad explícita ... startActivity desde una preferenciaActividad
A continuación, intente lo mismo, pero con un PreferenceFragment para mostrar sus preferencias en lugar de una PreferenceActivity. De nuevo, ¿el cuadro de diálogo permanece visible cuando gira la pantalla?
Hasta ahora, he encontrado que el diálogo permanecerá visible si se utiliza una PreferenceActivity, pero no si se utiliza un PreferenceFragment. Observando el código fuente de DialogPreference , parece que el comportamiento correcto es que el cuadro de diálogo permanezca visible, ya que isDialogShowing
es la información de estado que se guarda cuando onSaveInstanceState()
se llama en la reorientación de la pantalla. Por lo tanto, creo que un error puede impedir que el PreferenceFragment (y todo lo que hay dentro de él) restaurar esa información de estado.
Si se trata de un error de Android, tiene implicaciones de gran alcance, ya que cualquiera que utilice PreferenceFragment no puede guardar y restaurar la información de estado.
¿Puede alguien confirmar? Si no es un error, ¿qué está pasando?
- Configuración del diseño de preferencias y cambio del atributo en él
- Android CheckBoxPreference - un / marque todas las preferencias
- SetHomeButtonEnabled en PreferenciaActividad y preferencia anidada
- La actividad de lanzamiento de la actividad de preferencia provoca la excepción de denegación de permisos
- No ActionBar en PreferenceActivity después de actualizar a Support Library v21
- PreferenceFragment crashing, objeto nulo Referencia
- SharedPreferences no se guardará / cargará en PreferenciaActividad
- Cree su propia preferencia de SwitchCompat
Finalmente descubierto una solución a este problema. Resulta que no es un error, sino un problema / supervisión en la documentación para desarrolladores de Android.
Usted ve, yo estaba siguiendo el tutorial PreferenceFragment aquí . Ese artículo le dice que haga lo siguiente para instanciar su PreferenceFragment dentro de una actividad:
public class SettingsActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Display the fragment as the main content. getFragmentManager().beginTransaction() .replace(android.R.id.content, new SettingsFragment()) .commit(); } }
El problema con esto es que cuando se cambia la orientación de la pantalla (o cualquier otra acción que destruye y vuelve a crear la actividad), su PreferenceFragment se creará dos veces , que es lo que hace que pierda su estado.
La primera creación se realizará a través de la llamada de la actividad a super.onCreate()
(que se muestra arriba), que llamará el método onActivityCreated()
para su PreferenceFragment () y el método onRestoreInstanceState()
para cada preferencia que contenga. Éstos restaurarán con éxito el estado de todo.
Pero una vez que esa llamada a super.onCreate()
devuelve, puede ver que el método onCreate()
entonces continuará para crear el PreferenceFragment una segunda vez. Debido a que es inútilmente creado de nuevo (y esta vez, sin información de estado!), Todo el estado que fue restaurado con éxito será completamente descartado / perdido. Esto explica por qué un DialogPreference que puede estar mostrando en el momento en que se destruye la actividad ya no será visible una vez que la actividad se vuelve a crear.
¿Cuál es la solución? Bueno, solo agrega un pequeño cheque para determinar si el PreferenceFragment ya se ha creado, así:
public class SettingsActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Fragment existingFragment = getFragmentManager().findFragmentById(android.R.id.content); if (existingFragment == null || !existingFragment.getClass().equals(SettingsFragment.class)) { // Display the fragment as the main content. getFragmentManager().beginTransaction() .replace(android.R.id.content, new SettingsFragment()) .commit(); } } }
O de otra manera es simplemente comprobar si onCreate()
está destinado a restaurar el estado o no, así:
public class SettingsActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { // Display the fragment as the main content. getFragmentManager().beginTransaction() .replace(android.R.id.content, new SettingsFragment()) .commit(); } } }
Así que supongo que la lección aprendida aquí es que onCreate()
tiene un doble rol: puede configurar una Actividad por primera vez, o puede restaurar desde un estado anterior.
La respuesta aquí me llevó a darme cuenta de esta solución.
Yo mismo he tenido este problema. Hay un error donde el DialogFragment
no restaura el estado porque es nulo, o al menos me pasó a mí.
El uso de múltiples fuentes que finalmente tiene una solución de trabajo. Haga que su diálogo extienda este BaseDialogFragment
:
import android.app.Dialog; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.support.v4.app.DialogFragment; import com.actionbarsherlock.app.SherlockDialogFragment; public class BaseDialogFragment extends DialogFragment { @Override public void onCreate(Bundle savedInstanceState) { if (savedInstanceState == null || savedInstanceState.isEmpty()) savedInstanceState = WorkaroundSavedState.savedInstanceState; setRetainInstance(true); Log.d("TAG", "saved instance state oncreate: " + WorkaroundSavedState.savedInstanceState); super.onCreate(savedInstanceState); } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { if (savedInstanceState == null || savedInstanceState.isEmpty()) savedInstanceState = WorkaroundSavedState.savedInstanceState; Log.d("TAG", "saved instance state oncretaedialog: " + WorkaroundSavedState.savedInstanceState); return super.onCreateDialog(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (savedInstanceState == null || savedInstanceState.isEmpty()) savedInstanceState = WorkaroundSavedState.savedInstanceState; Log.d("TAG", "saved instance state oncretaeview: " + WorkaroundSavedState.savedInstanceState); return super.onCreateView(inflater, container, savedInstanceState); } @Override public void onDestroyView() // necessary for restoring the dialog { if (getDialog() != null && getRetainInstance()) getDialog().setOnDismissListener(null); super.onDestroyView(); } @Override public void onSaveInstanceState(Bundle outState) { // ... super.onSaveInstanceState(outState); WorkaroundSavedState.savedInstanceState = outState; Log.d("TAG", "saved instance state onsaveins: " + WorkaroundSavedState.savedInstanceState); } @Override public void onDestroy() { WorkaroundSavedState.savedInstanceState = null; super.onDestroy(); } /** * Static class that stores the state of the task across orientation * changes. There is a bug in the compatibility library, at least as of the * 4th revision, that causes the save state to be null in the dialog's * onRestoreInstanceState. */ public static final class WorkaroundSavedState { public static Bundle savedInstanceState; } }
Tenga en cuenta que en cualquier subclases cuyos métodos tienen un parámetro savedInstanceState
, es posible que tenga que llamar a super con WorkaroundSavedState.savedInstanceState
. Y cuando se está restaurando el estado (es decir, en onCreate()
, simplemente ignore el savedInstanceState
y en su lugar use WorkaroundSavedState.savedInstanceState
soporte estático no es la solución más limpia, pero funciona.Sólo asegúrese de establecerlo en null en su onDestroy()
.
En cualquier caso, mi DialogFragment
no desaparece cuando hago girar la pantalla (y eso es sin ningún configChanges
). Déjeme saber si este código se ocupa de su problema y si no voy a echar un vistazo a lo que está pasando. También tenga en cuenta que no he probado esto dentro de PreferenceFragment
pero en su lugar otro Fragment
de la clase de compatibilidad o de ActionBarSherlock
.