Search code examples
androidandroid-linearlayoutdevice-orientation

Programmatically Adding Views to Parent LinearLayout Duplicates Last Entry when Rotating Device


I've only been doing android programming for a few months, so I could be doing something silly here...

In my activity, I'm using a layout file with a LinearLayout that I'm programmatically adding child views to in the activity's OnCreate(). There is a layout file for the child view, and it contains 3 EditTexts that I'm populating with data I have saved somewhere.

When I navigate to the activity and onCreate() is first called, every child view is populated how I would expect. However, if I rotate the display from portrait -> landscape or vice-versa, when the page refreshes, all child views have the content of the last child view. When I step through the code with breakpoints, everything looks fine to me: the parent LinearLayout has the expected child views, and the child views are populated with the expected data. So, I'm at a loss as to why all child views have the data from the last child, and why this only happens when rotating. I'm using the same layout files here regardless of device size or orientation.

Any thoughts?

edit_profile_activity.xml:

<android.support.design.widget.CoordinatorLayout
    ...>

    <android.support.design.widget.AppBarLayout
        ...>

        <android.support.v7.widget.Toolbar
            .../>

    </android.support.design.widget.AppBarLayout>

    <!-- The main content view -->
    <android.support.v4.widget.NestedScrollView
        ...>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:scrollbarAlwaysDrawVerticalTrack="true"
            android:focusable="true"
            android:focusableInTouchMode="true">

            <!-- Edit Allies -->
            <LinearLayout
                android:id="@+id/profile_edit_ally_layout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:paddingLeft="@dimen/left_margin"
                android:paddingRight="@dimen/right_margin"
                android:orientation="vertical">

                <!-- This content is added programmatically. -->

            </LinearLayout>

        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>

edit_profile_activity_ally_list_item.xml:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <EditText
        android:id="@+id/profile_edit_ally_name_edit_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:hint="Name"
        android:imeOptions="flagNoExtractUi"
        android:inputType="textNoSuggestions"
        android:maxLines="1"
        android:privateImeOptions="nm"
        android:selectAllOnFocus="true"
        android:textAppearance="@style/FontEditText"/>
    <EditText
        android:id="@+id/profile_edit_ally_init_mod_edit_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_marginLeft="@dimen/left_margin"
        android:hint="Init Mod"
        android:imeOptions="flagNoExtractUi"
        android:inputType="numberSigned"
        android:maxLines="1"
        android:privateImeOptions="nm"
        android:selectAllOnFocus="true"
        android:textAppearance="@style/FontEditText"/>
    <EditText
        android:id="@+id/profile_edit_ally_caster_level_edit_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_marginLeft="@dimen/left_margin"
        android:hint="Caster Level"
        android:imeOptions="flagNoExtractUi"
        android:inputType="numberSigned"
        android:maxLines="1"
        android:privateImeOptions="nm"
        android:selectAllOnFocus="true"
        android:textAppearance="@style/FontEditText"/>
    <ImageButton
        android:id="@+id/profile_edit_delete_ally_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:background="@drawable/ic_delete"/>
</LinearLayout>

In my activity:

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);

    // Set the content of the activity to use the activity_main.xml layout file
    setContentView(R.layout.edit_profile_activity);

    // ...

    mAllyLayout = (LinearLayout) findViewById(R.id.profile_edit_ally_layout);
    for (TreeMap.Entry<String, AllyDB_Data> entry : mProfileData.mAllies.entrySet())
    {
        addAllyRowToLayout(entry.getKey(),
            Integer.toString(entry.getValue().mCasterLevel),
            Integer.toString(entry.getValue().mInitMod));
    }

    // Make sure there's at least one "empty" ally set.
    if (mAllyLayout.getChildCount() <= 0)
    {
        addAllyRowToLayout(null, null, null);
    }

    // ...
}

// ...

private void addAllyRowToLayout(String name, String casterLevel, String initMod)
{
    // Inflate the Ally Row
    View ally_layout_row = getLayoutInflater().inflate(R.layout.edit_profile_activity_ally_list_item, null, false);

    // EditText Name
    EditText name_edit_text = (EditText) ally_layout_row.findViewById(R.id.profile_edit_ally_name_edit_text);
    name_edit_text.setTextSize(14.0f);
    name_edit_text.setTextColor(Color.DKGRAY);
    if (name != null)
    {
        if (name.isEmpty() == false)
        {
            name_edit_text.setText(name);
        }
    }
    name_edit_text.addTextChangedListener(new TextWatcher()
    {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count)
        {
            invalidateOptionsMenu();
        }

        @Override
        public void afterTextChanged(Editable s) {}
    });

    // EditText Init Mod
    EditText init_mod_edit_text = (EditText) ally_layout_row.findViewById(R.id.profile_edit_ally_init_mod_edit_text);
    init_mod_edit_text.setTextSize(14.0f);
    init_mod_edit_text.setTextColor(Color.DKGRAY);
    if (initMod != null)
    {
        if (initMod.isEmpty() == false)
        {
            init_mod_edit_text.setText(initMod);
        }
    }

    // EditText Caster Level
    EditText caster_level_edit_text = (EditText) ally_layout_row.findViewById(R.id.profile_edit_ally_caster_level_edit_text);
    caster_level_edit_text.setTextSize(14.0f);
    caster_level_edit_text.setTextColor(Color.DKGRAY);
    if (casterLevel != null)
    {
        if (casterLevel.isEmpty() == false)
        {
            caster_level_edit_text.setText(casterLevel);
        }
    }

    // ImageButton Delete Ally Button
    ImageButton delete_button = (ImageButton) ally_layout_row.findViewById(R.id.profile_edit_delete_ally_button);
    delete_button.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            View parent_view = (View) v.getParent();
            if (parent_view != null)
            {
                mAllyLayout.removeView(parent_view);
            }
            if (mAllyLayout.getChildCount() == 0)
            {
                addAllyRowToLayout("", "", "");
            }
        }
    });

    // Add the Ally Row to the Ally Layout.
    mAllyLayout.addView(ally_layout_row);
}

Edit 1 There's an if statement in the activity's onCreate() that I failed to show when I first posted. if (allyLayout.getChildCount() <= 0) ...

Edit 2 Looking at this post gave me the idea to see what was happening in onRestoreInstanceState(Bundle savedInstanceState). Surprisingly to me, overriding it and making it empty, took care of my problem. I'm not sure if that's the most orthodox solution.


Solution

  • After this line :

    mAllyLayout = (LinearLayout) findViewById(R.id.profile_edit_ally_layout);
    

    Check if your linear layout has some views.

       if (mAllyLayout.getChildCount()>0){
        //add your views
    
        }
    

    Update If you don't want to handle data after rotation add this on your manifest:

    <activity
                android:name="Your activity"
                android:configChanges="orientation|keyboardHidden|screenSize"/>