Android CheckBox – Estado de restauración tras la rotación de la pantalla

He encontrado una funcionalidad muy inesperada (e increíblemente frustrante) al intentar restaurar el estado de una lista de CheckBox después de una rotación de pantalla. Pensé que primero trataría de dar una explicación textual sin el código, en caso de que alguien sea capaz de determinar una solución sin todos los detalles sangrientos. Si alguien necesita más detalles puedo publicar el código.

Tengo una lista de desplazamiento de las vistas complejas que contienen CheckBoxes. No he conseguido restaurar el estado de estas casillas de verificación después de una rotación de pantalla. He implementado onSaveInstanceState y han transferido con éxito la lista de cajas de verificación seleccionadas al método onCreate. Esto se maneja pasando un largo [] de id de base de datos al Bundle.

En onCreate () compruebo el paquete para la matriz de ids. Si la matriz está allí lo utilizo para determinar qué casillas de verificación para comprobar cuando se está construyendo la lista. He creado una serie de métodos de prueba y han confirmado que las casillas de verificación se están estableciendo correctamente, en función de la matriz de id. Como último cheque estoy comprobando los estados de todas las casillas de verificación al final de onCreate (). Todo se ve bien … a menos que gire la pantalla.

Cuando hago girar la pantalla, sucede una de dos cosas: 1) Si se selecciona alguna de las casillas de verificación, a excepción de la última, todas las casillas de verificación están desactivadas después de una rotación. 2) Si se comprueba la última casilla de verificación antes de la rotación, se comprueban todas las casillas de verificación después de la rotación.

Como he dicho, comprobar el estado de las cajas en el final de mi onCreate (). La cosa es, el estado de las cajas al final de onCreate es correcto basado en lo que he seleccionado antes de la rotación. Sin embargo, el estado de los cuadros en la pantalla no refleja esto.

Además, he implementado setOnCheckChangedListener () de cada casilla de verificación y he confirmado que el estado de mis casillas de verificación está siendo alterado después de que regrese mi método onCreate.

¿Alguien tiene una idea de lo que está pasando? ¿Por qué cambiaría el estado de mis casillas de verificación después de que regrese el método onCreate?

Gracias de antemano por tu ayuda. He estado tratando de degub esto por un par de días ahora. Después de que me encontré con que mis cajas estaban aparentemente cambiando en algún lugar fuera de mi propio código me imaginé que era el momento de preguntar alrededor.

Tuve un problema similar. La aplicación tenía varias casillas de verificación en la pantalla.
Después de girar la aplicación de teléfono era 'manual' el valor de configuración para todas las casillas de verificación.
Este código se ejecutó en onStart ().
Pero en la pantalla todas las casillas de verificación se establecieron con el valor de "última casilla de verificación" en la pantalla.
Android llamaba onRestoreInstanceState (..) y de alguna manera estaba tratando todas las casillas de verificación como 'una' [última de la pantalla].

La solución era desactivar "restaurar el estado de la instancia":

<RadioButton ... android:saveEnabled="false" /> 

todo el mundo. Parece que me di cuenta de esto. El estado de las casillas de verificación está siendo alterado en onRestoreInstanceState (Bundle). Este método se llama después de onCreate () (más precisamente, después de onStart ()), y es otro lugar donde Android recomienda restaurar el estado.

Ahora, no tengo ni idea de por qué mis casillas de verificación están siendo alteradas en onRestoreInstanceState, pero al menos sé que es donde el problema está ocurriendo. Sorprendentemente, cuando anula onRestoreInstanceState y no hago absolutamente nada (ninguna llamada a super.onRestoreInstanceState) toda la actividad funciona perfectamente.

Si alguien puede decirme por qué el estado seleccionado de las casillas de verificación se está cambiando en este método me gustaría mucho saber. En mi opinión, esto parece un error dentro del propio código de Android.

Si alguna vez encuentra algo más sobre este problema, por favor hágamelo saber. Me enfrenté esencialmente a este problema exactamente el mismo, y sólo la onRestoreInstanceState() funcionó. Muy raro.

Rpond, no he sobrepasado onResume, así que no creo que ese sea el problema. Aquí está la Actividad y los diseños asociados para que todos los vean. En el código verá muchas sentencias Log.d (hubo incluso más en un punto.) Con estas instrucciones de registro, pude verificar que el código funciona exactamente como esperaba. También, observe el onCheckChangedListener que agrego a cada CheckBox. Todo lo que hace es imprimir una declaración de registro que me dice el estado de uno de mis CheckBoxes cambiado. Fue a través de esto que pude determinar el estado de los cuadros de comprobación estaban siendo alterados después de mi onCreate regresa. Verá cómo llamo examineCheckboxes () al final de mi onCreate. Las sentencias Log producidas a partir de esto no son lo que se muestra en mi pantalla después de una rotación, y puedo ver el estado de mis cuadros siendo alterados después (debido a la onCheckChangedListener).

SelectItems.java:

Public class SelectItems extends Actividad {

 public static final int SUCCESS = 95485839; public static final String ITEM_LIST = "item list"; public static final String ITEM_NAME = "item name"; // Save state constants private final String SAVE_SELECTED = "save selected"; private DbHelper db; private ArrayList<Long> selectedIDs; ArrayList<CheckBox> cboxes = new ArrayList<CheckBox>(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.select_items); // Create database helper db = new DbHelper(this); db.open(); initViews(savedInstanceState); examineCheckboxes(); } private void initViews(Bundle savedState) { initButtons(); initHeading(); initList(savedState); } private void initButtons() { // Setup event for done button Button doneButton = (Button) findViewById(R.id.done_button); doneButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { done(); } }); // Setup event for cancel button Button cancelButton = (Button) findViewById(R.id.cancel_button); cancelButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { cancel(); } }); } private void initHeading() { String itemName = getIntent().getExtras().getString(ITEM_NAME); TextView headingField = (TextView) findViewById(R.id.heading_field); if (itemName.equals("")) { headingField.setText("No item name!"); } else { headingField.setText("Item name: " + itemName); } } private void initList(Bundle savedState) { // Init selected id list if (savedState != null && savedState.containsKey(SAVE_SELECTED)) { long[] array = savedState.getLongArray(SAVE_SELECTED); selectedIDs = new ArrayList<Long>(); for (long id : array) { selectedIDs.add(id); } Log.d("initList", "restoring from saved state"); logIDList(); } else { selectedIDs = (ArrayList<Long>) getIntent().getExtras().get( ITEM_LIST); Log.d("initList", "using database values"); logIDList(); } // Begin building item list LayoutInflater li = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); LinearLayout scrollContent = (LinearLayout) findViewById(R.id.scroll_content); Cursor cursor = db.getAllItems(); startManagingCursor(cursor); cursor.moveToFirst(); // For each Item entry, create a list element while (!cursor.isAfterLast()) { View view = li.inflate(R.layout.item_element, null); TextView name = (TextView) view.findViewById(R.id.item_name); TextView id = (TextView) view.findViewById(R.id.item_id); CheckBox cbox = (CheckBox) view.findViewById(R.id.checkbox); name.setText(cursor.getString(cursor .getColumnIndexOrThrow(DbHelper.COL_ITEM_NAME))); final long itemID = cursor.getLong(cursor .getColumnIndexOrThrow(DbHelper.COL_ID)); id.setText(String.valueOf(itemID)); // Set check box states based on selectedIDs array if (selectedIDs.contains(itemID)) { Log.d("set check state", "setting check to true for " + itemID); cbox.setChecked(true); } else { Log.d("set check state", "setting check to false for " + itemID); cbox.setChecked(false); } cbox.setOnClickListener(new OnClickListener() { public void onClick(View v) { Log.d("onClick", "id: " + itemID + ". button ref: " + ((CheckBox) v)); checkChanged(itemID); } }); //I implemented this listener just so I could see when my //CheckBoxes were changing. Through this I was able to determine //that my CheckBoxes were being altered outside my own code. cbox.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton arg0, boolean arg1) { Log.d("check changed", "button: " + arg0 + " changed to: " + arg1); } }); cboxes.add(cbox); scrollContent.addView(view); cursor.moveToNext(); } cursor.close(); examineCheckboxes(); } private void done() { Intent i = new Intent(); i.putExtra(ITEM_LIST, selectedIDs); setResult(SUCCESS, i); this.finish(); } private void cancel() { db.close(); finish(); } private void checkChanged(long itemID) { Log.d("checkChaged", "checkChanged for: "+itemID); if (selectedIDs.contains(itemID)) { selectedIDs.remove(itemID); } else { selectedIDs.add(itemID); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); long[] array = new long[selectedIDs.size()]; for (int i = 0; i < array.length; i++) { array[i] = selectedIDs.get(i); } outState.putLongArray(SAVE_SELECTED, array); } //Debugging method used to see what is in selectedIDs at any point in time. private void logIDList() { String list = ""; for (long id : selectedIDs) { list += id + " "; } Log.d("ID List", list); } //Debugging method used to check the state of all CheckBoxes. private void examineCheckboxes(){ for(CheckBox cbox : cboxes){ Log.d("Check Cbox", "obj: "+cbox+" checked: "+cbox.isChecked()); } } 

}

Select_items.xml:

 <?xml version="1.0" encoding="utf-8"?> 

 <TextView android:id="@+id/heading_field" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dip" android:textSize="18sp" android:textStyle="bold" /> <LinearLayout android:id="@+id/button_layout" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true"> <Button android:id="@+id/done_button" android:layout_weight="1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Done" /> <Button android:id="@+id/cancel_button" android:layout_weight="1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Cancel" /> </LinearLayout> <ScrollView android:orientation="vertical" android:layout_below="@id/heading_field" android:layout_above="@id/button_layout" android:layout_width="fill_parent" android:layout_height="wrap_content"> <LinearLayout android:id="@+id/scroll_content" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> </LinearLayout> </ScrollView> 

Item_element.xml:

 <?xml version="1.0" encoding="utf-8"?> 

 <CheckBox android:id="@+id/checkbox" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_marginRight="5dip" /> <TextView android:id="@+id/item_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp" android:layout_centerVertical="true" android:layout_toLeftOf="@id/checkbox" android:layout_alignParentLeft="true" /> <TextView android:id="@+id/item_id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="invisible" /> 

Probablemente el problema es que cuando onRestoreInstanceState(Bundle) se llama restablece algunos o todos los "ajustes" de su aplicación a la puesta en marcha "predeterminados". La mejor manera de resolver esto es a través de las llamadas al método del ciclo de vida de la aplicación y la gestión. Además, cada vez que se cambia algo en la aplicación que no desea perder, guarde el cambio en saveInstanceState(Bundle) o cree su propio Bundle() para mantener los cambios temporalmente hasta que pueda mantener los cambios en un archivo o Algo, su bastante fácil pasar un paquete a través de una intención entre las actividades. Cómo ahorras lo que necesites ahorrar dependiendo de cuánto tiempo necesites retener los "ajustes".

Me he encontrado con esto también. Debe restaurar el estado de la casilla de verificación en onRestoreInstanceState () en lugar de onCreate ().

La actividad se destruye cuando la orientación de la pantalla cambia y onRestoreInstanceState () se llama después de onCreate (). Dado que la implementación primaria / principal de onRestoreInstanceState () restaura automáticamente el estado en Views with IDs, está restaurando las casillas de verificación después de onCreate () y clobbering – aparentemente debido a que tienen el mismo ID (framework bug?).

http://developer.android.com/reference/android/app/Activity.html

http://developer.android.com/reference/android/app/Activity.html#onRestoreInstanceState(android.os.Bundle)

También puede utilizar onSaveInstanceState(Bundle savedInstanceState) y onRestoreInstanceState(Bundle savedInstanceState)

ejemplo

 @Override public void onSaveInstanceState(Bundle savedInstanceState) { // EditTexts text savedInstanceState.putString("first_et",((EditText)findViewById(R.id.et_first)).getText().toString()); // EditTexts text savedInstanceState.putInt("first_et_v", ((EditText)findViewById(R.id.et_first)).getVisibility()); super.onSaveInstanceState(savedInstanceState); } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); // EditTexts text ((EditText)findViewById(R.id.et_first)).setText(savedInstanceState.getString("first_et")); // EditText visibility ((EditText)findViewById(R.id.et_first)).setVisibility(savedInstanceState.getInt("first_et_v")); } 

Hay una solución que es más fácil de explicar.

Android CHECKBOXES y RADIOBUTTON y RADIOGROUPS se comportan extrañamente si el atributo "id" no está establecido en ellos.

Tuve exactamente el mismo problema en mi código, y después de haber colocado ids en las casillas de verificación, comenzó a trabajar, sin tener que deshabilitar cualquiera de los métodos de superclase.

Tengo el mismo problema y la solución fue:

 <CheckBox ... android:saveEnabled="false" /> 
  • Android: Rotación de la imagen alrededor del centro
  • Rotación de ImageView desde el archivo xml de diseño
  • Compatibilidad con la versión de la API de Android
  • ¿Cómo obtener el valor de zoom de la matriz arbitraria?
  • Gire la vista de disposición de androide sobre su centro usando el oyente táctil
  • WheelView no rellena el padre
  • Android, ¿Cómo puedo girar una flecha (imagen) alrededor de un punto fijo?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.