之前自己定义了一个AlertDialog对话框,第一次点击时正常。但第二次调用时会出现错误:java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
关于这个错误纠结了我好久。在网上百度了也不少,但感觉解决效果都达不到自己想要的效果。
网上的解释说是一个子视图指定了多个父视图。
由此能够判断出。在第二次点击button弹出对话框时。子视图与第一次点击时的子视图是同一个对象。而父视图已经不再是同一个对象了。
但感觉说的云里雾里的。经过我研究之后,发现了我觉得的非常好的解决方法。想分享给大家交流一下。
代码例如以下所看到的:
builder = new AlertDialog.Builder(MainActivity.this);
builder.setView(null);
builder.setView(dialogview);
builder.setTitle("记账");
builder.setPositiveButton("确定", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
MySQLiteOpenHelper helper = new MySQLiteOpenHelper(
MainActivity.this);
SQLiteDatabase database = helper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("sum", editText.getText().toString());
values.put(
"project",
spinner.getItemAtPosition(
(int) spinner.getSelectedItemId())
.toString());
if (checkBox.isChecked()) {
values.put("category", "收入");
}
if (checkBox2.isChecked()) {
values.put("category", "支出");
}
TextView textView = (TextView) view
.findViewById(R.id.textView1);
values.put("date", textView.getText().toString());
database.update("budget", values, "date=?",
new String[] { textView.getText().toString() });
dialogview=null;
if(dialogview==null){
dialogview = getLayoutInflater().inflate(R.layout.add_dialog, null);
editText = (EditText) dialogview.findViewById(R.id.editText1);
spinner = (Spinner) dialogview.findViewById(R.id.spinner1);
checkBox = (CheckBox) dialogview.findViewById(R.id.checkBox1);
checkBox2 = (CheckBox) dialogview.findViewById(R.id.checkBox2);
clock = (DigitalClock) dialogview.findViewById(R.id.digitalClock2);
flag=true;
}
loaderManager.getLoader(1001).onContentChanged();// 若状态改变。触发这种方法
}
});
builder.setNegativeButton("取消", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
dialogview=null;
if(dialogview==null){
dialogview = getLayoutInflater().inflate(R.layout.add_dialog, null);
editText = (EditText) dialogview.findViewById(R.id.editText1);
spinner = (Spinner) dialogview.findViewById(R.id.spinner1);
checkBox = (CheckBox) dialogview.findViewById(R.id.checkBox1);
checkBox2 = (CheckBox) dialogview.findViewById(R.id.checkBox2);
clock = (DigitalClock) dialogview.findViewById(R.id.digitalClock2);
flag=true;
}
}
});
builder.create().show();
}
});
我自己定义了一个dialog,里头包括checkbox控件和spinner控件,我想依据checkbox空间的勾选情况动态spinner的内容,因此我将其定义为了全局变量,以此就造成了我上述所说的问题。
网友建议呢自己定义的view不应该设置为全局变量。应该设置为局部变量。Alert.builder创建一次。view通过getLayoutInflater获取一次就不会有二次点击对话框的问题。但这样就影响了我程序的效果。
依据我自己的不断探索,发现报错的原因时,由于我的view设置的为全局变量,在第一次创建对话框的时候,已经绑定了一个builder(也就是上次所说的Parent对象),所以在第二次点击对话框的时候,再次绑定builder的时候,新的builder就不会接收我们自己定义的view。由于它觉得你已经绑定过了,此时就算你将之前的builder在对话框消受的同一时候销毁掉也是无用的,由于我们的view仍然会有绑定的过往记录。
那么该怎样解决呢。我的解决方法是每次对话框完毕任务消失时,就将view置为null,又一次动态获取一次布局,事实上也就是为了实现近似于局部变量的效果。但要注意自己定义布局的控件也要随之findViewByid一遍。要不然你在第二次点击对话框时候是无法对该控件影响的。