2

The Context

My application architecture is very similar to the default called "Swipe Views" when you create a new android project. One activity, 3 Fragments, you can swipe through them. It uses the support library. everything is up to date. The device I'm testing on is a galaxy nexus running android 4.1.2 Support library r11, and SDK versions min=14 target=16

The Problem

The second Fragment holds a bunch of EditText which contain various numerical values read from sharedPreferences. When the Activity is first created, everything is fine the EditViews all have their correct value, but if I modify one of the values to, for instance 555, and then I rotate the device, all the EditText are now displaying 555 !

There is only one setText in the whole program and it is displayed later in this post, I tried to remove it, as expected when starting the activity all the EditTexts display the default value (666), I modify one and rotate the device, they all display the new value!

The details

One activity with a SectionsPagerAdapter, a ViewPager and several fragments for each page.

In one of the fragments (ConfigurationFragment) in the onViewCreated method I dynamically create lines with and EditText and an ImageButton.

those lines are actually in a layout (xml file) which I inflate for each line to add, then I get the editText and call setText to set it's value to what it should be.

onViewCreated method:

public void onViewCreated(View view, Bundle savedInstanceState)
{
    // populate ports list on view creation
    ArrayList<String> listenPorts = mServerManagerThread.getListenPorts();
    for (String port : listenPorts)
    {
        EditText v = ((EditText) addListenPortItem().getChildAt(0));
        v.setText(port);
    }

    super.onViewCreated(view, savedInstanceState);
}

naturally the method getListenPorts returns the same list each time it is called (on startup and when the device is rotated)

what addListenPortItem basically does:

    // Instantiate a new "row" view.
    final ViewGroup newView = (ViewGroup) LayoutInflater.from(viewGroup.getContext()).inflate(itemResource,
            viewGroup, false);

    // Set a click listener for the "X" button in the row that will remove
    // the row.
    newView.findViewById(R.id.delete_button).setOnClickListener(
            new OnRemoveClickListener(mContainer, viewGroup, newView, emptyListTextResource));

    viewGroup.addView(newView);

viewGroup is a linearLayout which will hold the newly created views itemResource is the following layout

layout of one line:

<?xml version="1.0" encoding="utf-8"?>
<!--
     <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="?android:listPreferredItemHeightSmall"
    android:layout_marginTop="8dp"
    android:divider="?android:dividerVertical"
    android:dividerPadding="8dp"
    android:gravity="right"
    android:orientation="horizontal"
    android:showDividers="middle" >

    <EditText
        android:id="@+id/editPort"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:ems="10"
        android:inputType="number"
        android:text="666" >
    </EditText>

    <ImageButton
        android:id="@+id/delete_button"
        style="?android:attr/borderlessButtonStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:contentDescription="@string/action_remove_item"
        android:src="@drawable/content_remove" />
</LinearLayout>

any idea?

I've been staring at this bug for a couple hours now and I really have no clue what's going on ... I'm starting to suspect a bug in the SDK or the support library, but I know from experience the bug is most often in my brain :)

Code-Apprentice
  • 69,701
  • 17
  • 115
  • 226
f4.
  • 3,755
  • 1
  • 20
  • 30

2 Answers2

4

I found the solution: I moved the code from onViewCreated to onViewStateRestored(..) so that filling the EditTexts with their value is done after the state has been restored.

The problem was that all the EditTexts have the same id so when restoring the state it was messing it up.

f4.
  • 3,755
  • 1
  • 20
  • 30
  • Will you please mark this question as solved and explain it a bit more. Because i am also facing same problem but could not find proper solution though you said you have solved it .... – Parmeshwar C Jan 27 '14 at 10:16
  • 1
    @chavan I'm afraid I don't remember much of this problem, but I guess the problem was that I inflate n times the same layout, so all the EditTexts have the same id (android:id="@+id/editPort"). When the device is rotated, the view is recreated, and values put back in place using the ids ... I guess. But they all have the same so it doesn't work. The solution at the time was to override the value afterward, and you'd do that in onViewStateRestored(). Is it any clearer? – f4. Jan 31 '14 at 10:55
  • Yes, i also had this problem due to including layout multiple times resulting in multiple occurences of the same view id. Your answer was instrumental in finding the cause. All EditText values where set equal when device rotated. I fixed this with `myView.setId(View.generateViewId());` when creating it, as seen on https://stackoverflow.com/a/15442898/2096041 .. feels like a workaround tho. – Barry Staes May 23 '18 at 08:24
0

That's not a bug, so don't be worried. The problem is that if you rotate the screen the Activity and the Fragments will be recreated. onCreateView() will be called again and this mixes things up and therefore you have such a weird behaviour. You can fix this by overriding these thwo methods:

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    // Read values from the "savedInstanceState"-object and put them in your textview
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    // Save the values you need from your textview into "outState"-object
    super.onSaveInstanceState(outState);
}
Ahmad
  • 58,947
  • 17
  • 107
  • 133
  • I know onCreateView is being called again, so is the code which re-adds the lines with the editTexts and sets their value – f4. Nov 21 '12 at 23:27
  • In `onSaveInstanceState()` you can save your values. So if the screen gets rotated `onCreateView()` will get called and `onCreateView` takes a Bundle as a param, which happens to be the Bundle `onRestoreInstanceState` passes. – Ahmad Nov 21 '12 at 23:33
  • refere to this question: http://stackoverflow.com/questions/7951730/viewpager-and-fragments-whats-the-right-way-to-store-fragments-state – Ahmad Nov 21 '12 at 23:34
  • I know that but I don't see how it's going to help since the values are not the problem, I get them through the call to getListenPorts – f4. Nov 21 '12 at 23:37
  • Not helpful. The actual root cause is as follow : http://stackoverflow.com/questions/13914970/why-edittext-in-a-custom-compound-view-is-re-using-the-text-entered-in-another-c Use tag instead of id as a workaround of this problem (or bug). – Cheok Yan Cheng Apr 08 '13 at 11:44