Il figlio specificato ha già un genitore. Devi prima chiamare removeView () sul genitore del bambino (Android)


164

Devo passare frequentemente tra due layout. L'errore si sta verificando nel layout pubblicato di seguito.

Quando il mio layout viene chiamato la prima volta, non si verifica alcun errore e tutto va bene. Quando chiamo quindi un layout diverso (uno vuoto) e successivamente chiamo il mio layout una seconda volta, viene generato il seguente errore:

> FATAL EXCEPTION: main
>     java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

Il mio codice di layout è simile al seguente:

    tv = new TextView(getApplicationContext()); // are initialized somewhere else
    et = new EditText(getApplicationContext()); // in the code


private void ConsoleWindow(){
        runOnUiThread(new Runnable(){

     @Override
     public void run(){

        // MY LAYOUT:
        setContentView(R.layout.activity_console);
        // LINEAR LAYOUT
        LinearLayout layout=new LinearLayout(getApplicationContext());
        layout.setOrientation(LinearLayout.VERTICAL);
        setContentView(layout);

        // TEXTVIEW
        layout.addView(tv); //  <==========  ERROR IN THIS LINE DURING 2ND RUN
        // EDITTEXT
        et.setHint("Enter Command");
        layout.addView(et);
        }
    }
}

So che questa domanda è stata posta prima, ma nel mio caso non ha aiutato.


1
Solo per qualcuno che ha lo stesso errore: assicurati di aggiungere l'elemento corretto. Diciamo che devi aggiungere LinearLayoutma tu aggiungi TextView. Quindi aggiustalo.
Sviluppatore

quando si utilizza la banca dati Android non dovrebbe dichiarare la vista con ID 'root', causa lo stesso errore.
Mohammad Reza Khahani,

per quelli che usano TranstitionManager.beginDelayedTransition, controlla qui la
mochadwi

Risposte:


354

Il messaggio di errore dice cosa dovresti fare.

// TEXTVIEW
if(tv.getParent() != null) {
    ((ViewGroup)tv.getParent()).removeView(tv); // <- fix
}
layout.addView(tv); //  <==========  ERROR IN THIS LINE DURING 2ND RUN
// EDITTEXT

56

passare semplicemente l'argomento attachtoroot come falso

View view = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, false);

2
Per me, questo era un cretino. Layout del vincolo per gli elementi in un recycleView, modificando dinamicamente i vincoli in base al runtime. ConstraintSet.apply non ha funzionato, fino a questo. Quindi, propaga il genitore in onCreateViewHolder, ma invia false come parametro adizionale al gonfiamento.
miroslavign

3
Questa è la soluzione giusta! Come ha detto @Sniper, passare null al secondo parametro può far sì che la vista figlio non si allinei come dovrebbe con il suo genitore. OTOH che passa il genitore può causare l'errore in questione. Quindi, attachToRoot= false, è la strada da percorrere.
Vassilis,

Il modo corretto di farlo.
Rowland Mtetezi,

50

Sono venuto qui per cercare l'errore con il mio recyclerview ma la soluzione non ha funzionato (ovviamente). Ho scritto la causa e la soluzione per essa in caso di recyclerview. Spero che aiuti qualcuno.

L'errore è causato se si onCreateViewHolder()segue il seguente metodo:

layoutInflater = LayoutInflater.from(context);
return new VH(layoutInflater.inflate(R.layout.single_row, parent));

Invece dovrebbe essere

return new VH(layoutInflater.inflate(R.layout.single_row, null));

15
A volte le risposte casuali che non sono esattamente le risposte alle domande poste aiutano qualcun altro. Questo ha funzionato per me. Grazie!
Ajith Memana,

1
Bello !, ed è per questo che le persone dovrebbero quasi sempre passare "null" come parametri 2d nei gonfiatori. Grazie.
superUser

4
Passare Null al parametro responsabile per il genitore non è una cattiva idea, ma devi sapere che in questo caso la vista figlio (quella che gonfia) non sarà in grado di misurarsi correttamente in alcuni casi, perché non lo fa sapere qualcosa del genitore. In alcuni casi funzionerà, ma in alcuni no.
Stoycho Andreev,

1
Si noti che ciò potrebbe causare la risoluzione corretta del tema dei viewholder.
SpaceBison,

13

Ho ricevuto questo messaggio mentre cercavo di eseguire il commit di un frammento usando attach to root su true anziché su false, in questo modo:

return inflater.inflate(R.layout.fragment_profile, container, true)

Dopo aver fatto:

return inflater.inflate(R.layout.fragment_profile, container, false)

Ha funzionato.


5

Se un'altra soluzione non funziona come:

View view = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, false);

controlla cosa stai restituendo da onCreateView del frammento è vista singola o viewgroup? nel mio caso avevo viewpager su root di xml di frammento e stavo restituendo viewpager, quando ho aggiunto viewgroup nel layout non ho aggiornato che ora devo restituire viewgroup, non viewpager (view).


5

frameLayout.addView (bannerAdView); <----- se ricevi un errore su questa linea, fai come sotto.

if (bannerAdView.getParent() != null)

  ((ViewGroup) bannerAdView.getParent()).removeView(bannerAdView);

   frameLayout.addView(bannerAdView);     <------ now added view

4

Il mio errore è stato definire la vista in questo modo:

view = inflater.inflate(R.layout.qr_fragment, container);

Mancava:

view = inflater.inflate(R.layout.qr_fragment, container, false);

3

Nel mio caso il problema era causato dal fatto che gonfiavo Vista genitore con <merge>layout. In questo caso, ha addView()causato l'incidente.

View to_add = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, true);
// parent_layout.addView(to_add); // THIS CAUSED THE CRASH

La rimozione ha addView()aiutato a risolvere il problema.


2

controlla se hai già aggiunto la vista

if (textView.getParent() == null)
    layout.addView(textView);

2

Il codice qui sotto lo ha risolto per me:

@Override
public void onDestroyView() {
    if (getView() != null) {
        ViewGroup parent = (ViewGroup) getView().getParent();
        parent.removeAllViews();
    }
    super.onDestroyView();
}

Nota: l'errore proveniva dalla mia classe di frammenti e sostituendo il metodo onDestroy in questo modo, ho potuto risolverlo.


2
if(tv!= null){
    ((ViewGroup)tv.getParent()).removeView(tv); // <- fix
}

2

Nel mio caso succede quando voglio aggiungere la vista per genitore ad un'altra vista

View root = inflater.inflate(R.layout.single, null);
LinearLayout lyt = root.findViewById(R.id.lytRoot);
lytAll.addView(lyt);  // ->  crash

devi aggiungere la vista padre in questo modo

View root = inflater.inflate(R.layout.single, null);
LinearLayout lyt = root.findViewById(R.id.lytRoot);
lytAll.addView(root);

2

Devi prima rimuovere la vista figlio dal suo genitore.

Se il tuo progetto è in Kotlin, la tua soluzione avrà un aspetto leggermente diverso da Java. Kotlin semplifica il casting con as?, restituendo null se il lato sinistro è null o il cast fallisce.

(childView.parent as? ViewGroup)?.removeView(childView)
newParent.addView(childView)

Soluzione di estensione Kotlin

Se devi farlo più di una volta, aggiungi questa estensione per rendere il tuo codice più leggibile.

childView.removeSelf()

fun View?.removeSelf() {
    this ?: return
    val parentView = parent as? ViewGroup ?: return
    parentView.removeView(this)
}

Non farà nulla in modo sicuro se questa vista è nulla, la vista padre è nulla o la vista padre non è un gruppo di viste


1

Ho trovato un'altra soluzione:

if (mView.getParent() == null) {
                    myDialog = new Dialog(MainActivity.this);
                    myDialog.setContentView(mView);
                    createAlgorithmDialog();
                } else {
                    createAlgorithmDialog();
                }

Qui ho solo un'istruzione if controlla se la vista aveva un genitore e se non ha creato la nuova finestra di dialogo, imposta contentView e mostra la finestra di dialogo nel mio metodo "createAlgorithmDialog ()".

Questo imposta anche i pulsanti positivi e negativi (pulsanti ok e annulla) con onClickListeners.


0

È possibile utilizzare questo metodo per verificare se una vista ha figli o meno.

public static boolean hasChildren(ViewGroup viewGroup) {
    return viewGroup.getChildCount() > 0;
 }

0

Il mio caso era diverso la vista figlio aveva già una vista padre Sto aggiungendo la vista figlio all'interno della vista padre a padre diverso. codice di esempio di seguito

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/lineGap"
>
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="@color/black1"
    android:layout_gravity="center"
    android:gravity="center"
    />

</LinearLayout>

E stavo gonfiando questa vista e aggiungendo a un altro LinearLayout, quindi ho rimosso il LinaarLayout dal layout sopra e ha iniziato a funzionare

sotto il codice risolto il problema:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:gravity="center"
   android:textColor="@color/black1" />

0

Il mio problema è legato a molte altre risposte, ma un motivo un po 'diverso per la necessità di apportare la modifica ... Stavo cercando di convertire un'attività in un frammento. Quindi ho spostato il codice di gonfiaggio da onCreate a onCreateView, ma ho dimenticato di convertire da setContentView al metodo infllate e lo stesso IllegalStateException mi ha portato a questa pagina.

Ho cambiato questo:

binding = DataBindingUtil.setContentView(requireActivity(), R.layout.my_fragment)

a questa:

binding = DataBindingUtil.inflate(inflater, R.layout.my_fragment, container, false)

Ciò ha risolto il problema.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.