rotacion - manejando la rotación de pantalla en android studio
¿Por qué Fragment no conservará el estado cuando se gira la pantalla? (2)
De hecho, he tenido este problema yo mismo. Hay un error donde DialogFragment
no restaura el estado porque es nulo, o al menos me sucedió a mí.
Utilizando múltiples fuentes finalmente conseguí una solución funcionando. 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 subclase cuyos métodos tengan un parámetro savedInstanceState
, es posible que tenga que llamar a super con WorkaroundSavedState.savedInstanceState
. Y cuando esté restableciendo el estado (es decir, en onCreate()
, simplemente ignore el estado de savedInstanceState
y en su lugar use WorkaroundSavedState.savedInstanceState
. El soporte estático no es la solución más limpia, pero funciona. Solo asegúrese de configurarlo en su onDestroy()
.
En cualquier caso, mi DialogFragment
no desaparece cuando giro la pantalla (y eso sin configChanges
). Avíseme si este código aborda su problema y, si no, echaré un vistazo a lo que está sucediendo. También tenga en cuenta que no he probado esto en PreferenceFragment
sino en otros Fragment
de la clase de compatibilidad o de ActionBarSherlock
.
He tenido problemas para obtener algunas subclases DialogPreference personalizadas dentro de un Fragmento de Preferencias para que permanezcan visibles cuando se gira la pantalla. No experimento este problema cuando uso una actividad de preferencia, por lo que no sé si es un error de Android o un problema con mi código, pero me gustaría que alguien confirmara si tienen la misma experiencia.
Para probar esto, primero crea una pantalla de preferencias que contenga al menos una DialogPreference (no importa qué subclase). Luego muéstralo en una actividad de preferencia. Cuando ejecutas tu aplicación, presiona DialogPreference para que se muestre el cuadro de diálogo. Luego gire la pantalla para que la orientación cambie. ¿El diálogo permanece visible?
Luego intente lo mismo, pero con un PreferenceFragment para mostrar sus preferencias en lugar de una PreferenceActivity. Nuevamente, ¿el diálogo permanece visible cuando gira la pantalla?
Hasta ahora, he encontrado que el diálogo permanecerá visible si se usa una actividad de preferencia, pero no si se usa un Fragmento de preferencia. Al isDialogShowing
el código fuente de DialogPreference , parece que el comportamiento correcto es que el diálogo permanezca visible, porque isDialogShowing
es la información de estado que se guarda cuando onSaveInstanceState()
se onSaveInstanceState()
en la reorientación de la pantalla. Por lo tanto, creo que un error puede impedir que el PreferenceFragment (y todo lo que contiene) restituya 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.
¿Alguien puede confirmar? Si no es un error, ¿qué está pasando?
Finalmente encontré una solución a este problema. Resulta que no es un error, sino un problema / supervisión en la documentación del desarrollador de Android.
Verá, estaba siguiendo el tutorial PreferenceFragment here . Ese artículo te dice que hagas lo siguiente para crear una instancia de tu 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 cambias la orientación de la pantalla (o cualquier otra acción que destruya y vuelva a crear la Actividad), tu 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 super.onCreate()
a super.onCreate()
(que se muestra arriba), que llamará al método onActivityCreated()
para su PreferenceFragment () y el método onRestoreInstanceState()
para cada Preference que contenga. Estos restaurarán con éxito el estado de todo.
Pero una vez que esa llamada a super.onCreate()
vuelve, puede ver que el método onCreate()
continuará para crear el PreferenceFragment por segunda vez. Debido a que se crea sin sentido de nuevo (¡y esta vez, sin información de estado!), Todo el estado que se restauró con éxito se descartará / perderá por completo. Esto explica por qué una DialogPreference que puede mostrarse en el momento en que se destruye la actividad ya no será visible una vez que la actividad se vuelva a crear.
Entonces, ¿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 bien, otra forma es simplemente verificar 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 que se aprende aquí es que onCreate()
tiene una doble función: puede configurar una actividad por primera vez o puede restaurar desde un estado anterior.
La respuesta here me llevó a darme cuenta de esta solución.