Androidcheckbox – 屏幕旋转后恢复状态

我遇到了一些非常意想不到的(令人难以置信的令人沮丧的)function,同时尝试恢复屏幕旋转后的CheckBox列表的状态。 我想我首先会尝试给出一个没有代码的文本解释,以防有人能够确定一个没有所有血腥细节的解决scheme。 如果有人需要更多的细节,我可以发布代码。

我有一个包含checkbox的复杂视图的滚动列表。 在屏幕旋转后,我还没有成功恢复这些checkbox的状态。 我已经实现了onSaveInstanceState,并已成功地将所选checkbox的列表传递给onCreate方法。 这是通过将一个长的[]数据库ID传递给Bundle来处理的。

在onCreate()我检查捆绑的ID数组。 如果数组在那里,我使用它来确定列表正在构build时要检查哪些checkbox。 我已经创build了许多testing方法,并且已经确认checkbox正在根据id数组正确设置。 作为最后一个检查,我正在检查onCreate()最后的所有checkbox的状态。 一切看起来不错…除非我旋转屏幕。

当我旋转屏幕时,会发生以下两种情况之一:1)如果select了任意数量的checkbox,除最后一个外,所有checkbox在旋转后均closures。 2)如果最后一个checkbox在旋转之前被选中,则所有checkbox在旋转之后被选中

就像我所说的,我在onCreate()的最后检查框的状态。 事情是,onCreate结束框的状态是正确的,根据我select旋转之前。 但是,屏幕上方框的状态并不反映这一点。

另外,我已经实现了每个checkbox的setOnCheckChangedListener(),并且我已经确认我的onCreate方法返回 ,我的checkbox的状态正在被改变。

任何人都知道发生了什么? 为什么在我的onCreate方法返回后,我的checkbox的状态会改变?

在此先感谢您的帮助。 现在我一直试图消除这一点。 当我发现我的checkbox显然是在我自己的代码之外的某个地方发生改变的时候,我想是时候到处打听了。

Solutions Collecting From Web of "Androidcheckbox – 屏幕旋转后恢复状态"

我有类似的问题。 应用程序在屏幕上有几个checkbox。
旋转手机应用程序后,手动设置所有checkbox的值。
这段代码是在onStart()中执行的。
但是在屏幕上,所有的checkbox都是在屏幕上设置了“最后一个checkbox”的值。
Android正在调用RestoreInstanceState(..),并以某种方式将所有checkbox视为“一个”(从屏幕上的最后一个)。

解决scheme是禁用“恢复实例状态”:

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

大家。 看来我明白了这一点。 checkbox的状态正在onRestoreInstanceState(Bundle)中被更改。 这个方法在onCreate()之后被调用(更确切地说,在onStart()之后),并且是Androidbuild议恢复状态的另一个地方。

现在,我不知道为什么我的checkbox正在onRestoreInstanceState内被改变,但至less我知道这是问题发生的地方。 令人惊讶的是,当我重写onRestoreInstanceState和完全没有(没有调用super.onRestoreInstanceState)整个活动完美的作品。

如果有人可以告诉我为什么checkbox的select状态正在改变这种方法,我非常想知道。 在我看来,这看起来像在Android代码本身的错误。

如果您还发现有关此问题的更多信息,请告诉我。 我基本上面对这个完全相同的问题,只有重写onRestoreInstanceState()工作。 很奇怪。

Rpond,我没有覆盖ResResume,所以我不认为这是问题。 这是活动和相关的布局,供大家看到。 在代码中,您将看到许多Log.d语句(甚至还有更多的)。通过这些Log语句,我可以validation代码是否按照我所期望的那样工作。 另外,请注意我添加到每个CheckBox的onCheckChangedListener。 它所做的就是打印一条Log语句,告诉我一个CheckBox的状态发生了变化。 正是通过这个,我才能确定CheckBoxes在我的onCreate返回后被改变的状态。 你会看到我在我的onCreate结尾处如何调用examineCheckboxes()。 由此产生的Log语句并不是在旋转后在屏幕上显示的内容,而且之后我可以看到我的框的状态被改变(因为onCheckChangedListener)。

SelectItems.java:

公共类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)被调用时,它会将应用程序的一些或全部“设置”重置为启动“默认”。 解决此问题的最佳方法是通过应用程序生命周期方法调用和pipe理。 此外,任何时候你的应用程序中有些东西是你不想松动的,把改变保存到saveInstanceState(Bundle)或者创build你自己的Bundle()来暂时保存这些改变,直到你可以把改变保存在一个文件中,或者它很容易通过活动之间的意图传递一个捆绑。 如何保存您需要保存的内容取决于您需要保留“设置”的时间长度。

我也遇到了这个。 您应该在onRestoreInstanceState()而不是onCreate()中恢复checkbox状态。

当屏幕方向改变时,活动被破坏,onCreate()之后调用onRestoreInstanceState()。 由于onRestoreInstanceState()的父/默认实现会自动恢复ID为Views的状态,因此它会在onCreate()之后恢复checkbox并将其复位 – 显然是由于它们具有相同的ID(框架错误?)。

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

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

你也可以使用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")); } 

有一个解决scheme更容易解释。

如果没有设置“id”属性,Android CHECKBOXES和RADIOBUTTON和RADIOGROUPS的行为会变得很奇怪。

我在代码中遇到了完全相同的问题,在将checkbox上的id置入后,它开始工作,不必禁用任何超类方法。