应用在 removeView 上崩溃
app crashes on removeView
我编写了以下应用程序,其中显示了 3 x 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;
}
}
}
这个特定部分有些奇怪:
public void deleteSomething(){
((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(0);
((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(1);
((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(2);
}
把前两行注释掉,第二行第三个按钮就可以顺利删除了;注释掉第二个,第二个中的前两个按钮也可以毫无问题地删除。但是,当您包含所有这三行时,应用程序会在您单击下拉菜单中的第一项后立即崩溃。
有人知道为什么吗?
问题
您的问题是您按索引引用视图。每删除一次视图,children 的数量就会减少。让我们看看您的示例:
LinearLayout以3开头children:
[甲、乙、丙]
第一次通话
((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(0);
现在你的 LinearLayout 有 2 children:
[乙,丙]
执行下一个调用
((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(1);
现在你的 LinearLayout 有 1 个 child:
[B]
执行下一个调用
(LinearLayout) linearLayout.getChildAt(1)).removeViewAt(2);
这会引发异常,因为索引 2 超出了 children(现在大小为 1)的范围。
解决方案
首先获取对您要删除的任何视图的引用。然后使用 removeView(View view)
从 LayoutGroup 中删除它们。下面是一个简单的示例,说明您可以如何进行演示:
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);
首先感谢dharms的解释。没有 his/her 响应,我将无法想出这个解决方案。虽然 his/her 解释很有帮助,但 his/her 提出的解决方案不正确。我会 post 一个正确的解决方案如下:
改变这个
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);
}
}
}
基本思路是删除的时候不想改变id,所以要倒过来引用他们的id。
我编写了以下应用程序,其中显示了 3 x 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;
}
}
}
这个特定部分有些奇怪:
public void deleteSomething(){
((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(0);
((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(1);
((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(2);
}
把前两行注释掉,第二行第三个按钮就可以顺利删除了;注释掉第二个,第二个中的前两个按钮也可以毫无问题地删除。但是,当您包含所有这三行时,应用程序会在您单击下拉菜单中的第一项后立即崩溃。
有人知道为什么吗?
问题
您的问题是您按索引引用视图。每删除一次视图,children 的数量就会减少。让我们看看您的示例:
LinearLayout以3开头children:
[甲、乙、丙]
第一次通话
((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(0);
现在你的 LinearLayout 有 2 children:
[乙,丙]
执行下一个调用
((LinearLayout) linearLayout.getChildAt(1)).removeViewAt(1);
现在你的 LinearLayout 有 1 个 child:
[B]
执行下一个调用
(LinearLayout) linearLayout.getChildAt(1)).removeViewAt(2);
这会引发异常,因为索引 2 超出了 children(现在大小为 1)的范围。
解决方案
首先获取对您要删除的任何视图的引用。然后使用 removeView(View view)
从 LayoutGroup 中删除它们。下面是一个简单的示例,说明您可以如何进行演示:
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);
首先感谢dharms的解释。没有 his/her 响应,我将无法想出这个解决方案。虽然 his/her 解释很有帮助,但 his/her 提出的解决方案不正确。我会 post 一个正确的解决方案如下: 改变这个
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);
}
}
}
基本思路是删除的时候不想改变id,所以要倒过来引用他们的id。