L'enfant spécifié a déjà un parent. Vous devez d'abord appeler removeView () sur le parent de l'enfant (Android)

164

Je dois souvent basculer entre deux mises en page. L'erreur se produit dans la mise en page publiée ci-dessous.

Lorsque ma mise en page est appelée la première fois, il ne se produit aucune erreur et tout va bien. Lorsque j'appelle ensuite une mise en page différente (une mise en page vide) et que j'appelle ensuite ma mise en page une deuxième fois, cela génère l'erreur suivante:

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

Mon code de mise en page ressemble à ceci:

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

Je sais que cette question a déjà été posée, mais cela n'a pas aidé dans mon cas.

blackst0ne
la source
1
Juste pour quelqu'un qui obtient la même erreur: assurez-vous d'ajouter l'élément correct. Disons que vous devez ajouter LinearLayoutmais vous ajoutez TextView. Alors réparez-le.
Développeur
lors de l'utilisation de la liaison de données Android ne doit pas déclarer la vue avec l'ID 'root', cela provoque la même erreur.
Mohammad Reza Khahani
pour ceux qui utilisent TranstitionManager.beginDelayedTransition, veuillez vérifier ma réponse ici
mochadwi

Réponses:

354

Le message d'erreur indique ce que vous devez faire.

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

passez simplement l'argument attachtoroot comme faux

View view = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, false);
Études de plomb
la source
2
Pour moi, c'était une cible. Disposition des contraintes pour les éléments d'un recycleView, modifiant dynamiquement les contraintes en fonction de l'exécution. ConstraintSet.apply n'a pas fonctionné, jusqu'à celui-ci. Donc, propagez le parent dans onCreateViewHolder, mais envoyez false comme paramètre supplémentaire à gonfler.
miroslavign
3
C'est la bonne solution! Comme @Sniper l'a dit, passer null au deuxième paramètre peut empêcher la vue enfant de s'aligner comme elle le devrait sur son parent. OTOH passant le parent peut provoquer l'erreur en question. Donc, attachToRoot= false, est la voie à suivre.
Vassilis
La bonne façon de le faire.
Rowland Mtetezi le
50

Je suis venu ici en recherchant l'erreur avec mon recyclerview mais la solution n'a pas fonctionné (évidemment). J'ai écrit la cause et la solution en cas de recyclage. J'espère que ça aide quelqu'un.

L'erreur est causée si onCreateViewHolder()la méthode suivante est suivie:

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

Au lieu de cela, il devrait être

return new VH(layoutInflater.inflate(R.layout.single_row, null));
suku
la source
15
Parfois, des réponses aléatoires qui ne sont pas exactement les réponses aux questions posées aident quelqu'un d'autre. Cela a fonctionné pour moi. Merci!
Ajith Memana
1
Nice !, et c'est pourquoi les gens devraient souvent passer "null" comme paramètres 2D dans les gonfleurs. Merci.
superUser
4
Passer Null au paramètre responsable du parent n'est pas une mauvaise idée, mais il faut savoir que dans ce cas la vue enfant (celle que vous gonflez) ne pourra pas se mesurer correctement dans certains cas, car elle ne le fait pas rien savoir sur le parent. Dans certains cas, cela fonctionnera, mais dans d'autres non.
Stoycho Andreev
1
Notez que cela peut entraîner une résolution incorrecte du thème des spectateurs.
SpaceBison
13

J'ai reçu ce message en essayant de valider un fragment en utilisant attach to root sur true au lieu de false, comme ceci:

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

Après avoir fait:

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

Ça a marché.

Hudson Pereira
la source
5

Si une autre solution ne fonctionne pas comme:

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

vérifier ce que vous retournez de onCreateView du fragment est-ce une vue unique ou un groupe de vues? dans mon cas, j'avais viewpager sur la racine du xml du fragment et je retournais viewpager, quand j'ai ajouté viewgroup dans la mise en page je n'ai pas mis à jour que je dois retourner viewgroup maintenant, pas viewpager (view).

blackHawk
la source
5

frameLayout.addView (bannerAdView); <----- si vous obtenez une erreur sur cette ligne, procédez comme suit.

if (bannerAdView.getParent() != null)

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

   frameLayout.addView(bannerAdView);     <------ now added view
Mayur Dabhi
la source
4

Mon erreur a été de définir la vue comme ceci:

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

Il manquait:

view = inflater.inflate(R.layout.qr_fragment, container, false);
Pedro Molina
la source
3

Dans mon cas, le problème était dû au fait que je gonflais la vue parent avec la <merge>mise en page. Dans ce cas, a addView()causé le crash.

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

La suppression a addView()aidé à résoudre le problème.

soshial
la source
2

vérifiez si vous avez déjà ajouté la vue

if (textView.getParent() == null)
    layout.addView(textView);
Dan Alboteanu
la source
2

Le code ci-dessous l'a résolu pour moi:

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

Remarque: L'erreur provenait de ma classe de fragment et en remplaçant la méthode onDestroy comme celle-ci, j'ai pu la résoudre.

AK 12
la source
2
if(tv!= null){
    ((ViewGroup)tv.getParent()).removeView(tv); // <- fix
}
Chandan Bera
la source
2

Dans mon cas, cela se produit lorsque je veux ajouter une vue par parent à une autre vue

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

vous devez ajouter une vue parent comme celle-ci

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

Vous devez d'abord supprimer la vue enfant de son parent.

Si votre projet est en Kotlin, votre solution sera légèrement différente de Java. Kotlin simplifie la conversion avec as?, en retournant null si le côté gauche est nul ou si la conversion échoue.

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

Solution d'extension Kotlin

Si vous devez le faire plusieurs fois, ajoutez cette extension pour rendre votre code plus lisible.

childView.removeSelf()

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

Il ne fera rien en toute sécurité si cette vue est nulle, la vue parente est nulle ou la vue parente n'est pas un groupe de vues

Gibolt
la source
1

J'ai trouvé une autre solution:

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

Ici, j'ai juste une instruction if pour vérifier si la vue avait un parent et si ce n'était pas le cas Créez la nouvelle boîte de dialogue, définissez le contentView et affichez la boîte de dialogue dans ma méthode "createAlgorithmDialog ()".

Cela définit également les boutons positifs et négatifs (boutons OK et Annuler) avec onClickListeners.

Joshua Orotayo
la source
0

Vous pouvez utiliser cette méthode pour vérifier si une vue a des enfants ou non.

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

Mon cas était différent, la vue enfant avait déjà une vue parent. J'ajoute la vue enfant à l'intérieur de la vue parent à un parent différent. exemple de code ci-dessous

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

Et j'ai gonflé cette vue et ajouté à un autre LinearLayout, puis j'ai supprimé le LinaarLayout de la disposition ci-dessus et il a commencé à fonctionner

le code ci-dessous a résolu le problème:

<?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" />
Irfan
la source
0

Mon problème est lié à de nombreuses autres réponses, mais une raison un peu différente pour avoir besoin de faire le changement ... J'essayais de convertir une activité en fragment. J'ai donc déplacé le code gonfler de onCreate vers onCreateView, mais j'ai oublié de convertir de setContentView à la méthode inflate, et la même exception IllegalStateException m'a amené à cette page.

J'ai changé ceci:

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

pour ça:

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

Cela a résolu le problème.

Daniel Gibby
la source