Das angegebene Kind hat bereits ein Elternteil. Sie müssen removeView () zuerst auf dem Elternteil des Kindes aufrufen (Android)


164

Ich muss häufig zwischen zwei Layouts wechseln. Der Fehler tritt im unten angegebenen Layout auf.

Wenn mein Layout zum ersten Mal aufgerufen wird, tritt kein Fehler auf und alles ist in Ordnung. Wenn ich dann ein anderes Layout (ein leeres) und anschließend ein zweites Mal mein Layout aufrufe, wird der folgende Fehler ausgegeben:

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

Mein Layout-Code sieht folgendermaßen aus:

    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);
        }
    }
}

Ich weiß, dass diese Frage schon einmal gestellt wurde, aber in meinem Fall hat sie nicht geholfen.


1
Nur für jemanden, der den gleichen Fehler erhält: Stellen Sie sicher, dass Sie das richtige Element hinzufügen. Nehmen wir an, Sie müssen hinzufügen, LinearLayoutaber Sie fügen hinzu TextView. Also repariere es.
Entwickler

Wenn Sie die Android-Datenbindung verwenden, sollte die Ansicht nicht mit der ID 'root' deklariert werden, da dies denselben Fehler verursacht.
Mohammad Reza Khahani

Für diejenigen TranstitionManager.beginDelayedTransition, die verwenden , überprüfen Sie bitte meine Antwort hier
Mochadwi

Antworten:


354

Die Fehlermeldung sagt, was Sie tun sollten.

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

56

Übergeben Sie einfach das attachtoroot-Argument als falsch

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

2
Für mich war das ein Volltreffer. Einschränkungslayout für Elemente in einer recycleView, wobei Einschränkungen basierend auf der Laufzeit dynamisch geändert werden. ConstraintSet.apply hat bis zu diesem Zeitpunkt nicht funktioniert. Propagieren Sie also Eltern in onCreateViewHolder, aber senden Sie false als zusätzlichen Parameter zum Aufblasen.
Miroslavign

3
Das ist die richtige Lösung! Wie @Sniper sagte, kann die Übergabe von null an den zweiten Parameter dazu führen, dass sich die untergeordnete Ansicht nicht wie gewünscht an ihrem übergeordneten Element ausrichtet. OTOH, das den Elternteil übergibt, kann den fraglichen Fehler verursachen. Also, attachToRoot= falsch, ist der richtige Weg.
Vassilis

Die richtige Art, es zu tun.
Rowland Mtetezi

50

Ich bin hierher gekommen, um den Fehler mit meinem Recyclerview zu suchen, aber die Lösung hat (offensichtlich) nicht funktioniert. Ich habe die Ursache und die Lösung für den Fall von recyclerview geschrieben. Hoffe es hilft jemandem.

Der Fehler wird verursacht, wenn onCreateViewHolder()die folgende Methode angewendet wird:

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

Stattdessen sollte es sein

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

15
Manchmal helfen zufällige Antworten, die nicht genau die Antworten auf gestellte Fragen sind, jemand anderem. Das hat bei mir funktioniert. Vielen Dank!
Ajith Memana

1
Schön!, Und deshalb sollten die Leute in Inflatern meistens "null" als 2d-Parameter übergeben. Vielen Dank.
SuperUser

4
Die Übergabe von Null an den für das übergeordnete Element verantwortlichen Parameter ist keine schlechte Idee, aber Sie müssen wissen, dass in diesem Fall die untergeordnete Ansicht (die Sie aufblasen) in einigen Fällen nicht in der Lage ist, sich selbst korrekt zu messen, da dies nicht der Fall ist weiß etwas über die Eltern. In einigen Fällen wird es funktionieren, in einigen jedoch nicht.
Stoycho Andreev

1
Beachten Sie, dass dies dazu führen kann, dass das Viewholder-Thema nicht korrekt aufgelöst wird.
SpaceBison

13

Ich habe diese Meldung erhalten, als ich versucht habe, ein Fragment mit attach to root auf true anstatt auf false zu übertragen:

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

Danach:

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

Es funktionierte.


5

Wenn eine andere Lösung nicht funktioniert wie:

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

Überprüfen Sie, ob Sie von onCreateView des Fragments zurückkehren. Ist es eine einzelne Ansicht oder eine Ansichtsgruppe? In meinem Fall hatte ich Viewpager im Stammverzeichnis von XML des Fragments und gab Viewpager zurück. Als ich Viewgroup im Layout hinzufügte, habe ich nicht aktualisiert, dass ich jetzt Viewgroup zurückgeben muss, nicht Viewpager (View).


5

frameLayout.addView (bannerAdView); <----- Wenn Sie in dieser Zeile einen Fehler erhalten, gehen Sie wie folgt vor.

if (bannerAdView.getParent() != null)

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

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

4

Mein Fehler war, die Ansicht wie folgt zu definieren:

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

Es fehlte:

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

3

In meinem Fall wurde das Problem durch die Tatsache verursacht, dass ich die übergeordnete Ansicht mit <merge>Layout aufgeblasen habe. In diesem Fall addView()verursachte der Absturz.

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

Das Entfernen addView()half, das Problem zu lösen.


2

Überprüfen Sie, ob Sie die Ansicht bereits hinzugefügt haben

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

2

Der folgende Code hat es für mich gelöst:

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

Hinweis: Der Fehler stammte aus meiner Fragmentklasse. Durch Überschreiben der onDestroy-Methode konnte ich ihn beheben.



2

In meinem Fall passiert es, wenn ich eine Ansicht des übergeordneten Elements zu einer anderen Ansicht hinzufügen möchte

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

Sie müssen eine übergeordnete Ansicht wie diese hinzufügen

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

2

Sie müssen zuerst die untergeordnete Ansicht aus der übergeordneten Ansicht entfernen.

Wenn sich Ihr Projekt in Kotlin befindet, sieht Ihre Lösung etwas anders aus als Java. Kotlin vereinfacht das Casting mit as?und gibt null zurück, wenn die linke Seite null ist oder das Casting fehlschlägt.

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

Kotlin-Erweiterungslösung

Wenn Sie dies mehrmals tun müssen, fügen Sie diese Erweiterung hinzu, um Ihren Code besser lesbar zu machen.

childView.removeSelf()

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

Es wird sicher nichts tun, wenn diese Ansicht null ist, die übergeordnete Ansicht null ist oder die übergeordnete Ansicht keine ViewGroup ist


1

Ich habe eine andere Lösung gefunden:

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

Hier habe ich nur eine if-Anweisung, um zu überprüfen, ob die Ansicht ein übergeordnetes Element hatte und ob das neue Dialogfeld nicht erstellt wurde. Legen Sie die Inhaltsansicht fest und zeigen Sie das Dialogfeld in meiner Methode "createAlgorithmDialog ()" an.

Dadurch werden auch die positiven und negativen Schaltflächen (OK- und Abbrechen-Schaltflächen) mit onClickListeners eingerichtet.


0

Mit dieser Methode können Sie überprüfen, ob eine Ansicht untergeordnete Elemente enthält oder nicht.

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

0

Mein Fall war anders. Die untergeordnete Ansicht hatte bereits eine übergeordnete Ansicht. Ich füge die untergeordnete Ansicht in der übergeordneten Ansicht einem anderen übergeordneten Element hinzu. Beispielcode unten

<?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>

Und ich habe diese Ansicht aufgeblasen und zu einem anderen LinearLayout hinzugefügt, dann habe ich das LinaarLayout aus dem obigen Layout entfernt und es hat angefangen zu funktionieren

Der folgende Code hat das Problem behoben:

<?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

Mein Problem hängt mit vielen anderen Antworten zusammen, aber ein etwas anderer Grund für die Notwendigkeit, die Änderung vorzunehmen ... Ich habe versucht, eine Aktivität in ein Fragment umzuwandeln. Also habe ich den Inflate-Code von onCreate nach onCreateView verschoben, aber ich habe vergessen, von setContentView in die Inflate-Methode zu konvertieren, und dieselbe IllegalStateException hat mich auf diese Seite gebracht.

Ich habe das geändert:

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

dazu:

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

Das hat das Problem gelöst.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.