2012-02-06 11 views
9

So che ci sono dozzine di domande che chiedono questo errore, ma nessuna delle soluzioni proposte sembra applicarsi al mio problema, almeno quello che vedo.Android: il bambino specificato ha già un genitore. Devi chiamare removeView() sul genitore del figlio prima

Ecco il mio registro:

java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first. 
    at android.view.ViewGroup.addViewInner(ViewGroup.java:1976) 
    at android.view.ViewGroup.addView(ViewGroup.java:1871) 
    at android.view.ViewGroup.addView(ViewGroup.java:1851) 
    at com.android.internal.app.AlertController.setupView(AlertController.java:365) 
    at com.android.internal.app.AlertController.installContent(AlertController.java:206) 
    at android.app.AlertDialog.onCreate(AlertDialog.java:251) 
    at android.app.Dialog.dispatchOnCreate(Dialog.java:307) 
    at android.app.Dialog.show(Dialog.java:225) 
    at com.company.MyApp.MyActivity$7.onItemClick(MyActivity.java:240) 
    at android.widget.AdapterView.performItemClick(AdapterView.java:284) 
    at android.widget.ListView.performItemClick(ListView.java:3513) 
    at android.widget.AbsListView$PerformClick.run(AbsListView.java:1812) 
    at android.os.Handler.handleCallback(Handler.java:587) 
    at android.os.Handler.dispatchMessage(Handler.java:92) 
    at android.os.Looper.loop(Looper.java:130) 
    at android.app.ActivityThread.main(ActivityThread.java:3683) 
    at java.lang.reflect.Method.invokeNative(Native Method) 
    at java.lang.reflect.Method.invoke(Method.java:507) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) 
    at dalvik.system.NativeStart.main(Native Method) 

Ecco MyActivity.java onCreate(). Puoi vedere che un generatore di finestre di dialogo è mostrato e ha alcuni valori. Sia myDialogLayout e myDialogBuilder sono membri della classe private

@Override 
public void onCreate(Bundle savedInstanceState) 
{ 
    // ... a bunch of init code... 

    // Create a dialog builder 
    myDialogLayout = getLayoutInflater().inflate(R.layout.leaving, null); 
    myDialogBuilder = new AlertDialog.Builder(this) 
     .setTitle("My Title") 
     .setView(myDialogLayout) 
     .setNegativeButton("Cancel", new DialogInterface.OnClickListener() 
     { 
      public void onClick(DialogInterface dialog, int which) {} 
     }); 

    // ... more code ... 
} 

Più tardi, quando un certo tasto è scattato nella mia attività, il myDialogBuilder è personalizzato un po 'e poi una finestra di dialogo viene creato e mostrato. myDialog è una variabile di classe privata/membro:

// Builder customized a bit 
myDialogBuilder 
    .setMessage("custom message here"); 

// Dialog created from Builder 
myDialog = myDialogBuilder.create(); 

// Dialog shown 
myDialog.show(); // <---- MyActivity.java Line: 240 

Quindi sul mio problema, quando clicco il mio tasto, la finestra di dialogo viene creato correttamente. Ma dopo aver premuto Annulla nella finestra di dialogo e poi premere di nuovo il pulsante, ottengo l'errore visto nel registro. Per qualche motivo, l'attività non vuole che riutilizzi la mia finestra di dialogo myDialog. È un membro della classe, quindi è accessibile dal gestore onClick. E lo myDialog è una nuova finestra di dialogo ogni volta che si fa clic sul pulsante, poiché viene creato da zero dallo myDialogBuilder.create() ogni volta.

Qualcuno sa qual è il problema? Ho anche provato ad aggiungere in myDialog.dismiss() quando viene premuto il pulsante Annulla, ma questo non ha fatto la differenza.

Inoltre, è possibile vedere nel mio myDialogBuilder che viene utilizzato un layout XML personalizzato per la visualizzazione della finestra di dialogo. Secondo il messaggio di errore, sembrava che volesse che io usassi removeView() per rimuovere la vista dall'essere utilizzata nella finestra di dialogo. Ma myDialogBuilder.removeView() non è un metodo valido.

risposta

17

è myDialogLayout una variabile membro della classe? Se è così allora ha già un genitore dalla prima volta che mostri la finestra di dialogo, quindi crei una seconda finestra di dialogo che prova anche a essere la genitrice di myDialogLayout. Prova a creare una nuova istanza di myDialogLayout ogni volta che apri la finestra di dialogo.

+2

Questa era la chiave.Ho rimosso 'myDialogLayout' dall'essere una variabile membro della classe e invece lo ho reso locale al metodo del gestore' onClick'. In questo modo è un nuovo layout che viene gonfiato ogni volta. Grazie! –

3

Questo è un esempio primario del motivo per cui è consigliato l'uso dei metodi onCreateDialog() onPrepareDialog().

Se si sta istanziando myDialog ogni volta che si preme il pulsante, si sta tentando di collegare le viste dall'oggetto di dialogo precedentemente creato (il vecchio genitore) alla nuova finestra di dialogo.

Un dialogo che è stato istanziato, mostrato e chiuso, deve semplicemente essere mostrato di nuovo, non completamente ricreato.

Supponendo che myDialog sia un membro della classe, provare a verificare se myDialog è null o meno. Se non è null, mostralo di nuovo invece di istanziarlo completamente.

MODIFICA - Ecco un esempio di cosa intendo, utilizzando onPrepareDialog() e onCreateDialog(). In Crea crea la finestra di dialogo, e ogni volta che viene mostrato, viene preparato e si ottiene un riferimento a EditText usando findViewById e il testo cancellato. Supponiamo che DIALOG_TEST sia una costante intera e che in layout/dialog_test.xml sia presente una vista EditText con id edittext.

@Override 
protected void onPrepareDialog(int id, Dialog dialog) { 

    switch(id){ 

    case DIALOG_TEST: 

     EditText mEditText = (EditText) dialog.findViewById(R.id.edittext); 
     mEditText.setText(""); 
     break; 
    } 

} 

@Override 
protected Dialog onCreateDialog(int id) { 

    AlertDialog.Builder builder = new AlertDialog.Builder(this); 

    switch(id){ 

    case DIALOG_TEST: 

     LinearLayout layout = (LinearLayout) ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.dialog_test, null); 

     builder.setTitle("Enter Something").setView(layout); 
     return builder.create(); 
    } 
} 
+0

La finestra di dialogo deve essere creata perché il suo messaggio (e altri aspetti di esso) sono diversi ogni volta. –

+0

Le finestre di dialogo hanno un metodo findViewById. Dovresti usarlo per ottenere un riferimento alle viste e quindi aggiornarle. – Maximus

+0

Sì, ne sono consapevole. Sto anche modificando il comportamento 'onClick' per il pulsante positivo ogni volta. Non ho menzionato questo nel post originale sopra solo per semplificare l'esempio. –

Problemi correlati