El niño especificado ya tiene un padre. Primero debe llamar a removeView () en el padre del niño (Android)

164

Tengo que cambiar entre dos diseños con frecuencia. El error está ocurriendo en el diseño publicado a continuación.

Cuando se llama mi diseño por primera vez, no se produce ningún error y todo está bien. Cuando llamo a un diseño diferente (uno en blanco) y luego llamo a mi diseño por segunda vez, arroja el siguiente error:

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

Mi código de diseño se ve así:

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

Sé que esta pregunta se ha hecho antes, pero no ayudó en mi caso.

blackst0ne
fuente
1
Solo para alguien que recibe el mismo error: asegúrese de agregar el elemento correcto. Digamos que tienes que agregar LinearLayoutpero tú agregas TextView. Así que arréglalo.
Desarrollador
cuando se usa el enlace de datos de Android no se debe declarar la vista con el ID 'root', causa el mismo error.
Mohammad Reza Khahani
para aquellos que usan TranstitionManager.beginDelayedTransition, compruebe mi respuesta aquí
mochadwi

Respuestas:

354

El mensaje de error dice lo que debe hacer.

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

simplemente pasa el argumento attachtoroot como falso

View view = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, false);
Estudios de Pb
fuente
2
Para mí, esto fue una diana. Diseño de restricciones para elementos en un recycleView, que cambia dinámicamente las restricciones en función del tiempo de ejecución. ConstraintSet.apply no funcionó, hasta este. Por lo tanto, propague padre en onCreateViewHolder, pero envíe falso como parámetro adicional para inflar.
miroslavign
3
¡Esta es la solución correcta! Como dijo @Sniper, pasar nulo al segundo parámetro puede hacer que la vista secundaria no se alinee como debería con su padre. OTOH pasar al padre puede causar el error en cuestión. Entonces, attachToRoot= falso, es el camino a seguir.
Vassilis
La forma correcta de hacerlo.
Rowland Mtetezi
50

Vine aquí buscando el error con mi vista de reciclador pero la solución no funcionó (obviamente). He escrito la causa y la solución para ello en caso de una vista de reciclaje. Espero que ayude a alguien.

El error se produce si se onCreateViewHolder()sigue el siguiente método:

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

En cambio debería ser

return new VH(layoutInflater.inflate(R.layout.single_row, null));
suku
fuente
15
A veces, las respuestas aleatorias que no son exactamente las respuestas a las preguntas hechas ayudan a otra persona. Esto funcionó para mí. ¡Gracias!
Ajith Memana el
1
¡Bien !, y es por eso que la mayoría de las veces las personas deben pasar "nulo" como parámetros 2D en los infladores. Gracias.
superUser
44
Pasar Null al parámetro responsable del padre no es una mala idea, pero debe saber que, en este caso, la vista secundaria (la que infla) no podrá medirse correctamente en algunos casos, porque no saber algo sobre el padre En algunos casos funcionará, pero en otros no.
Stoycho Andreev
1
Tenga en cuenta que esto puede hacer que el tema de los lectores no se resuelva correctamente.
SpaceBison
13

Recibí este mensaje al intentar cometer un fragmento usando adjuntar a raíz a verdadero en lugar de falso, así:

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

Después de hacer:

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

Funcionó.

Hudson Pereira
fuente
5

Si otra solución no funciona como:

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

compruebe qué devuelve de onCreateView del fragmento, ¿es una vista única o un grupo de vista? en mi caso tenía viewpager en la raíz de xml de fragmento y estaba devolviendo viewpager, cuando agregué viewgroup en el diseño no actualicé que tengo que devolver viewgroup ahora, no viewpager (view).

blackHawk
fuente
5

frameLayout.addView (bannerAdView); <----- si obtiene un error en esta línea, haga lo siguiente ...

if (bannerAdView.getParent() != null)

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

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

Mi error fue definir la vista de esta manera:

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

Faltaba:

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

En mi caso, el problema fue causado por el hecho de que estaba inflando la Vista principal con el <merge>diseño. En este caso, addView()causó el accidente.

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

La eliminación addView()ayudó a resolver el problema.

soshial
fuente
2

compruebe si ya agregó la vista

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

El siguiente código lo resolvió para mí:

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

Nota: El error fue de mi clase de fragmentos y al anular el método onDestroy como este, pude resolverlo.

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

En mi caso, sucede cuando quiero agregar una vista de padre a otra vista

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

debes agregar una vista principal como esta

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

Primero debe eliminar la vista secundaria de su elemento primario.

Si su proyecto está en Kotlin, su solución se verá ligeramente diferente a Java. Kotlin simplifica el lanzamiento con as?, devolviendo nulo si el lado izquierdo es nulo o falla el lanzamiento.

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

Solución de extensión Kotlin

Si necesita hacer esto más de una vez, agregue esta extensión para que su código sea más legible.

childView.removeSelf()

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

No hará nada con seguridad si esta Vista es nula, la vista primaria es nula o la vista primaria no es un ViewGroup

Gibolt
fuente
1

Encontré otra solución:

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

Aquí solo tengo una instrucción if para verificar si la vista tenía un padre y si no lo hizo Crear el nuevo diálogo, establecer el contentView y mostrar el diálogo en mi método "createAlgorithmDialog ()".

Esto también configura los botones positivo y negativo (ok y cancelar botones) con onClickListeners.

Joshua Orotayo
fuente
0

Puede usar este método para verificar si una vista tiene hijos o no.

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

Mi caso era diferente, la vista secundaria ya tenía una vista principal. Estoy agregando la vista secundaria dentro de la vista principal a una vista principal diferente. ejemplo de código a continuación

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

Y estaba inflando esta vista y agregando a otro LinearLayout, luego eliminé el LinaarLayout del diseño anterior y comenzó a funcionar

El siguiente código solucionó el 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" />
Irfan
fuente
0

Mi problema está relacionado con muchas de las otras respuestas, pero una razón un poco diferente para necesitar hacer el cambio ... Estaba tratando de convertir una Actividad en un Fragmento. Así que moví el código de inflado de onCreate a onCreateView, pero olvidé convertir de setContentView al método de inflado, y la misma IllegalStateException me trajo a esta página.

Cambié esto:

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

a esto:

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

Eso resolvió el problema.

Daniel Gibby
fuente