Android CheckBox – восстановление состояния после вращения экрана

Я столкнулся с некоторыми очень неожиданными (и невероятно расстраивающими) функциями, пытаясь восстановить состояние списка CheckBoxes после поворота экрана. Я решил, что сначала попытаюсь дать текстовое объяснение без кода, если кто-то сможет определить решение без всех подробностей. Если кому-то нужно больше деталей, я могу опубликовать код.

У меня есть прокручиваемый список сложных представлений, содержащих CheckBoxes. Я не смог восстановить состояние этих флажков после поворота экрана. Я реализовал onSaveInstanceState и успешно передал список выбранных флажков методу onCreate. Это обрабатывается путем передачи длинного [] идентификаторов базы данных в Bundle.

В onCreate () я проверяю Bundle на массив идентификаторов. Если массив существует, я использую его, чтобы определить, какие флажки проверяются при создании списка. Я создал несколько методов тестирования и подтвердил правильность установки флажков на основе массива id. В качестве последней проверки я проверяю состояния всех флажков в самом конце onCreate (). Все выглядит хорошо … если я не поворачиваю экран.

Когда я поворачиваю экран, происходит одна из двух вещей: 1) Если выбрано любое количество флажков, кроме последнего, все флажки отключены после поворота. 2) Если последний флажок установлен перед вращением, все флажки проверяются после поворота.

Как я уже сказал, я проверяю состояние ящиков в самом конце моего onCreate (). Дело в том, что состояние ящиков в конце onCreate правильное на основе того, что я выбрал до поворота. Однако состояние ящиков на экране не отражает этого.

Кроме того, я выполнил каждый флажок setOnCheckChangedListener (), и я подтвердил, что состояние моих флажков изменяется после того, как возвращается метод onCreate.

Кто-нибудь имеет представление о том, что происходит? Почему изменилось состояние моих флажков после возврата метода onCreate?

Заранее спасибо за вашу помощь. Я пытаюсь разложить это на пару дней. После того, как я обнаружил, что мои флажки, очевидно, менялись где-то вне моего собственного кода, я подумал, что пришло время спросить.

Solutions Collecting From Web of "Android CheckBox – восстановление состояния после вращения экрана"

У меня была схожая проблема. У приложения было несколько флажков на экране.
После поворота приложения для телефона было установлено значение «вручную» для всех флажков.
Этот код был выполнен в onStart ().
Но на экране все флажки были установлены со значением «последний флажок» на экране.
Android вызывал onRestoreInstanceState (..) и как-то обрабатывал все флажки как «один» [последний с экрана].

Решение заключалось в том, чтобы отключить «восстановление состояния экземпляра»:

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

все. Похоже, я понял это. Состояние флажков изменяется в onRestoreInstanceState (Bundle). Этот метод вызывается после onCreate () (точнее, после onStart ()), и это другое место, где Android рекомендует восстановить состояние.

Теперь я понятия не имею, почему мои флажки изменяются внутри onRestoreInstanceState, но, по крайней мере, я знаю, что проблема возникает. Удивительно, но когда я переопределяю onRestoreInstanceState и ничего не делаю (нет вызова super.onRestoreInstanceState), вся деятельность работает отлично.

Если кто-нибудь скажет мне, почему выбранное состояние флажков изменяется в этом методе, я бы очень хотел узнать. По-моему, это выглядит как ошибка в самом коде Android.

Если вы когда-нибудь найдете что-нибудь еще об этой проблеме, сообщите мне. Я столкнулся по существу с той же самой проблемой и работал только над обработкой onRestoreInstanceState() . Очень странно.

Rpond, я не переоценил onResume, поэтому я не думаю, что это проблема. Здесь представлены действия и связанные макеты для всех. В коде вы увидите множество операторов Log.d (в какой-то момент их было еще больше.) С помощью этих операторов Log я смог проверить, работает ли код точно так, как я ожидаю. Также обратите внимание на onCheckChangedListener, который я добавляю в каждый CheckBox. Все, что он делает, это распечатать заявление журнала, в котором сообщается, что состояние одного из моих CheckBoxes изменено. Именно благодаря этому я смог определить, что состояние CheckBoxes было изменено после возвращения моего onCreate. Вы увидите, как я называю checkCheckboxes () в конце моего onCreate. Операторы журнала, созданные из этого, не являются тем, что показано на моем экране после поворота, и я могу видеть, что состояние моих ящиков изменяется после этого (из-за onCheckChangedListener.)

SelectItems.java:

Public class SelectItems расширяет действие {

 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" /> 

Вероятно, проблема в том, что всякий раз, когда onRestoreInstanceState(Bundle) называется, он сбрасывает некоторые или все «настройки» вашего приложения на начальные «значения по умолчанию». Лучший способ решить это – вызвать вызовы и управление методом жизненного цикла приложений. Кроме того, в любое время, когда что-то изменилось в вашем приложении, которое вы не хотите потерять, сохраните изменения в saveInstanceState(Bundle) или создайте свой собственный Bundle() чтобы временно удерживать изменения, пока вы не сможете сохранить изменения в файле или Что-то, его достаточно легко передать комплект через намерение между действиями. Как вы сохраняете все, что вам нужно, чтобы сохранить в зависимости от того, как долго вам нужно сохранить «настройки».

Я тоже столкнулся с этим. Вы должны восстановить состояние флажка в onRestoreInstanceState () вместо onCreate ().

Активность разрушается, когда изменения ориентации экрана и onRestoreInstanceState () вызывается после onCreate (). Поскольку исходная / стандартная реализация onRestoreInstanceState () автоматически восстанавливает состояние в представлениях с идентификаторами, он восстанавливает ваши флажки после onCreate () и сбивает их – по-видимому, из-за того, что они имеют одинаковый идентификатор (фрейм-ошибка?).

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

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

Вы также можете использовать onSaveInstanceState(Bundle savedInstanceState) и onRestoreInstanceState(Bundle savedInstanceState)

пример

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

Есть решение, которое легче объяснить.

Android CHECKBOXES и RADIOBUTTON и RADIOGROUPS ведут себя странно, если атрибут «id» не установлен на них.

У меня была такая же проблема в моем коде, и после того, как я установил флажки на флажках, он начал работать без необходимости отключать какие-либо методы суперкласса.

У меня та же проблема, и решение было:

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