旋转设备时以编程方式将视图添加到父 LinearLayout 会重复最后一个条目

Posted

技术标签:

【中文标题】旋转设备时以编程方式将视图添加到父 LinearLayout 会重复最后一个条目【英文标题】:Programmatically Adding Views to Parent LinearLayout Duplicates Last Entry when Rotating Device 【发布时间】:2017-11-15 17:23:27 【问题描述】:

我只做了几个月的android编程,所以我可能在这里做一些傻事......

在我的活动中,我正在使用带有 LinearLayout 的布局文件,我以编程方式将子视图添加到活动的 OnCreate() 中。子视图有一个布局文件,它包含 3 个 EditTexts,我用我保存在某处的数据填充它们。

当我导航到活动并首次调用 onCreate() 时,每个子视图都会填充 how I would expect。但是,如果我从纵向 -> 横向或反之旋转显示,当页面刷新时,all child views have the content of the last child view。当我使用断点单步执行代码时,对我来说一切都很好:父 LinearLayout 具有预期的子视图,而子视图填充了预期的数据。所以,我不知道为什么所有子视图都有来自最后一个孩子的数据,以及为什么这只发生在旋转时。无论设备大小或方向如何,我都在这里使用相同的布局文件。

有什么想法吗?

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_
            android:layout_
            android:orientation="vertical"
            android:scrollbarAlwaysDrawVerticalTrack="true"
            android:focusable="true"
            android:focusableInTouchMode="true">

            <!-- Edit Allies -->
            <LinearLayout
                android:id="@+id/profile_edit_ally_layout"
                android:layout_
                android:layout_
                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_
    android:layout_
    android:orientation="horizontal">
    <EditText
        android:id="@+id/profile_edit_ally_name_edit_text"
        android:layout_
        android:layout_
        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_
        android:layout_
        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_
        android:layout_
        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_
        android:layout_
        android:layout_gravity="center_vertical"
        android:background="@drawable/ic_delete"/>
</LinearLayout>

在我的活动中:

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

编辑 1 活动的 onCreate() 中有一条 if 语句,我在第一次发布时未能显示。 if (allyLayout.getChildCount() &lt;= 0) ...

编辑 2 看着this 的帖子让我想到了看看onRestoreInstanceState(Bundle savedInstanceState) 发生了什么。令我惊讶的是,覆盖它并使其为空,解决了我的问题。我不确定这是否是最正统的解决方案。

【问题讨论】:

【参考方案1】:

在这一行之后:

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

检查您的线性布局是否有一些视图。

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

    

更新 如果您不想在轮换后处理数据,请在清单中添加:

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

【讨论】:

感谢您的反馈,diegoveloper。首先,请注意我对上面的帖子进行了编辑。 (代码中有一条 if 语句我没有包含在内。)我尝试了您的建议,这就是我所看到的:当页面第一次导航到时,有一个空行。 (我所期望的。)如果填写该行并添加更多数据行,然后旋转屏幕,它会显示一行,其中包含旋转前最后一行的内容。这对我来说意味着旋转之前的一些数据会持续存在并覆盖我在第二轮中设置的数据。 这似乎有效。非常感谢您的帮助!我花了一整天的时间试图解决这个问题。我还注意到覆盖 onRestoreInstanceState() 和 not 调用超类也给了我预期的结果。我仍然不知道具体是什么超类在做什么,虽然这会导致问题,但我至少可以避免它。

以上是关于旋转设备时以编程方式将视图添加到父 LinearLayout 会重复最后一个条目的主要内容,如果未能解决你的问题,请参考以下文章

在需要时以编程方式添加滚动

需要时以编程方式添加滚动

如何以编程方式为其父视图添加视图大小?

如何将 SwiftUI 视图动态添加到父视图?

如何通过仅膨胀一次将相同的视图多次添加到父级

在运行时以编程方式激活约束