Android 应用程序在removeView上崩溃

Android 应用程序在removeView上崩溃,android,android-layout,android-linearlayout,programmatically,Android,Android Layout,Android Linearlayout,Programmatically,我编写了以下应用程序,其中显示了一个3×4的按钮网格,用户可以通过单击菜单项更改网格尺寸。问题是“deleteSomething”函数出现了一些奇怪的情况。以下是完整的代码: package com.example.myapplication; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.Gravity; import android.view.Me

我编写了以下应用程序,其中显示了一个3×4的按钮网格,用户可以通过单击菜单项更改网格尺寸。问题是“deleteSomething”函数出现了一些奇怪的情况。以下是完整的代码:

package com.example.myapplication;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {

    LinearLayout.LayoutParams params;
    LinearLayout linearLayout;
    int _row;
    int column;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        linearLayout = new LinearLayout(this);
        linearLayout.setOrientation(LinearLayout.VERTICAL);  //Can also be done in xml by android:orientation="vertical"
        params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
        params.weight = 1.0f;
        params.gravity = Gravity.TOP;
        //layout.setBackgroundColor(0xFFFFFFFF);
        _row=3;
        column=4;
        update();

    }


    public void update(){
        for (int i = 0; i < _row; i++) {
            LinearLayout row = new LinearLayout(this);
            row.setLayoutParams(params);

            for (int j = 0; j < column; j++) {
                Button btnTag = new Button(this);
                btnTag.setLayoutParams(params);
                btnTag.setText("Button " + (j + 1 + (i * column)));
                btnTag.setId(j + 1 + (i * column));
                if ((i+j) % 2 == 0) {
                    btnTag.setBackgroundColor(0xFFFF0000);
                } else {
                    btnTag.setBackgroundColor(0x00000000);
                }

                row.addView(btnTag);
            }
            linearLayout.addView(row);
        }

        setContentView(linearLayout);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add(Menu.NONE, 1, Menu.NONE, "Item name");
        menu.add(Menu.NONE, 2, Menu.NONE, "Item name");
        return true;
    }

    public void deleteSomething(){

        ((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(0);
        ((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(1);
        ((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(2);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
            case MENU_ITEM_ITEM1:
                deleteSomething();
                //linearLayout.removeAllViews();
                //_row=4;
                //column=5;
                //update();
                return true;
            case 2:
                deleteSomething();
                //linearLayout.removeAllViews();
                _row=6;
                column=3;
                update();
            default:
                return false;
        }


    }
}
注释掉前两行,第二行的第三个按钮被删除,没有问题;注释掉第二个按钮,第二个按钮中的前两个按钮也被删除,没有问题。但是,当您包含所有三行时,在单击下拉菜单中的第一项后,应用程序会立即崩溃


有人知道为什么吗?

这个问题

您的问题是您正在按索引引用视图。每次删除视图时,子视图的数量都会减少。让我们来看看你的例子:

线性布局从3个子项开始:
[甲、乙、丙]

第一次呼叫
((LinearLayout)LinearLayout.getChildAt(1)).removeViewAt(0)

现在,您的线性布局有2个子项:
[乙,丙]

执行下一个调用
((LinearLayout)LinearLayout.getChildAt(1)).removeViewAt(1)

现在,您的LinearLayout有1个子项:
[乙]

执行下一个调用
(LinearLayout)LinearLayout.getChildAt(1)).removeViewAt(2)

这会引发异常,因为索引2不在您的子项的范围内(现在大小为1)



解决方案

获取对要首先删除的任何视图的引用。然后使用
removeView(视图视图)
将它们全部从布局组中删除。下面是一个简单的示例,说明如何进行演示:

LinearLayout layout = (LinearLayout) linearLayout.getChildAt(1);
View a = layout.getChildAt(0);
View b = layout.getChildAt(1);
View c = layout.getChildAt(2);
layout.removeView(a);
layout.removeView(b);
layout.removeView(c);

首先,我要感谢达姆的解释。如果没有他/她的回答,我将无法想出这个解决方案。虽然他/她的解释很有帮助,但他/她提出的解决方案是不正确的。我将在以下内容中发布正确的解决方案: 改变这个

public void deleteSomething(){

    ((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(0);
    ((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(1);
    ((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(2);
}
致:


基本思想是我们不想在删除时更改ID,因此我们必须向后引用它们的ID。

我不想删除行。我实际上是在尝试删除行中的按钮。我认为最好的方法是向后引用它们的ID。这只是一个简单的例子。如果您总是按顺序删除一组子视图,那么有一个附加方法
removeViews(int start,int count)
将是一个更好的选择。我的示例介绍了您是否希望删除可能不按特定顺序排列的视图。
public void deleteSomething(){

    ((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(0);
    ((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(1);
    ((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(2);
}
public void deleteSomething(){
    for (int i = _row-1; i >= 0; i--) {
        for (int j = column - 1; j >= 0; j--) {
            ((LinearLayout) linearLayout.getChildAt(i)).removeViewAt(j);
        }
    }
}