標籤:android dialog 自訂 全域變數 局部變數
之前自訂了一個AlertDialog對話方塊,第一次點擊時正常,但第二次調用時會出現錯誤:java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child‘s parent first.
關於這個錯誤糾結了我好久,在網上百度了也不少,但感覺解決效果都達不到自己想要的效果。網上的解釋說是一個子視圖指定了多個父視圖。由此可以推斷出,在第二次點擊按鈕彈出對話方塊時,子視圖與第一次點擊時的子視圖是同一個對象,而父視圖已經不再是同一個對象了。但感覺說的雲裡霧裡的,經過我研究之後,發現了我認為的很好的解決方案,想分享給大家交流一下。
代碼如下所示:
builder = new AlertDialog.Builder(MainActivity.this);builder.setView(null); builder.setView(dialogview);builder.setTitle("記賬");builder.setPositiveButton("確定", new OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {// TODO Auto-generated method stubMySQLiteOpenHelper 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() {@Overridepublic void onClick(DialogInterface dialog, int which) {// TODO Auto-generated method stubdialogview=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一遍,要不然你在第二次點擊對話方塊時候是無法對該控制項影響的。