O filho especificado já tem um pai. Você deve chamar removeView () no pai da criança primeiro (Android)

164

Eu tenho que alternar entre dois layouts com frequência. O erro está ocorrendo no layout postado abaixo.

Quando meu layout é chamado pela primeira vez, não ocorre nenhum erro e está tudo bem. Quando eu chamo um layout diferente (em branco) e depois chamo meu layout pela segunda vez, ele gera o seguinte erro:

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

Meu código de layout é assim:

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

Sei que essa pergunta já foi feita antes, mas não ajudou no meu caso.

blackst0ne
fonte
1
Apenas para alguém que recebe o mesmo erro: adicione o elemento correto. Digamos que você precise adicionar, LinearLayoutmas você adiciona TextView. Então conserte.
Desenvolvedor
ao usar a ligação de dados do Android não deve declarar a visualização com o ID 'root', isso causa o mesmo erro.
Mohammad Reza Khahani 02/11/19
para aqueles que usam TranstitionManager.beginDelayedTransition, por favor, verifique minha resposta aqui
mochadwi

Respostas:

354

A mensagem de erro diz o que você deve fazer.

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

basta passar o argumento attachtoroot como false

View view = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, false);
Estudos Pb
fonte
2
Para mim, este foi um alvo. Layout de restrição para itens em um recycleView, alterando dinamicamente as restrições com base no tempo de execução. O ConstraintSet.apply não funcionou até este. Portanto, propague o pai no onCreateViewHolder, mas envie false como parâmetro adicional para aumentar.
miroslavign
3
Esta é a solução certa! Como o @Sniper disse, passar nulo para o segundo parâmetro pode fazer com que a visão filho não se alinhe como deveria ao pai. OTOH passando o pai pode causar o erro em questão. Então, attachToRoot= false, é o caminho a percorrer.
Vassilis
A maneira correta de fazer isso.
Rowland Mtetezi 04/07
50

Eu vim aqui pesquisando o erro com minha visão de reciclagem, mas a solução não funcionou (obviamente). Escrevi a causa e a solução para ela em caso de reciclagem. Espero que ajude alguém.

O erro é causado se onCreateViewHolder()o seguinte método for seguido:

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

Em vez disso, deve ser

return new VH(layoutInflater.inflate(R.layout.single_row, null));
suku
fonte
15
Às vezes, respostas aleatórias que não são exatamente as respostas para as perguntas feitas ajudam outra pessoa. Isso funcionou para mim. Obrigado!
precisa saber é o seguinte
1
Legal !, e é por isso que as pessoas na maioria das vezes passam "nulos" como parâmetros 2d nos infladores. Obrigado.
SuperUser 01/10/19
4
Passar Nulo para o parâmetro responsável pelo pai não é uma má ideia, mas você deve saber que, nesse caso, a visão filho (a que você inflou) não poderá medir a si mesma corretamente em alguns casos, porque não sabe alguma coisa sobre os pais. Em alguns casos, ele funcionará, mas em alguns não.
Stoycho Andreev
1
Observe que isso pode fazer com que o tema dos visualizadores não seja resolvido corretamente.
SpaceBison
13

Eu recebi esta mensagem ao tentar confirmar um fragmento usando o anexo para raiz como verdadeiro em vez de falso, da seguinte forma:

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

Depois de fazer:

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

Funcionou.

Hudson Pereira
fonte
5

Se outra solução não estiver funcionando como:

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

verifique o que você está retornando do onCreateView do fragmento. É uma visualização ou grupo de visualizações único? no meu caso, eu tinha o viewpager na raiz do xml do fragmento e estava retornando o viewpager, quando adicionei o viewgroup no layout, não atualizei que eu tinha que retornar o viewgroup agora, não o viewpager (view).

Falcão
fonte
5

frameLayout.addView (bannerAdView); <----- se você receber erro nesta linha, faça o seguinte abaixo ..

if (bannerAdView.getParent() != null)

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

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

Meu erro foi definir a visualização da seguinte maneira:

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

Faltava:

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

No meu caso, o problema foi causado pelo fato de eu estar inflando o View pai com o <merge>layout. Nesse caso, addView()causou o acidente.

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

A remoção addView()ajudou a resolver o problema.

soshial
fonte
2

verifique se você já adicionou a visualização

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

O código abaixo resolveu para mim:

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

Nota: O erro foi da minha classe de fragmento e, substituindo o método onDestroy como este, eu poderia resolvê-lo.

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

No meu caso, isso acontece quando eu quero adicionar a visualização pelos pais para outra visualização

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

você deve adicionar a visualização pai como esta

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

Você deve primeiro remover a visão filho do pai.

Se seu projeto estiver no Kotlin, sua solução parecerá um pouco diferente do Java. Kotlin simplifica a conversão com as?, retornando nulo se o lado esquerdo for nulo ou a conversão falhar.

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

Solução de extensão Kotlin

Se você precisar fazer isso mais de uma vez, adicione esta extensão para tornar seu código mais legível.

childView.removeSelf()

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

Ele não fará nada com segurança se essa Visualização for nula, a visualização pai for nula ou a visualização pai não for um ViewGroup

Gibolt
fonte
1

Encontrei outra correção:

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

Aqui, eu só tenho uma instrução if para verificar se o modo de exibição teve um pai e, se não criou o novo diálogo, defina o contentView e mostre o diálogo no meu método "createAlgorithmDialog ()".

Isso também define os botões positivo e negativo (botões ok e cancelar) com onClickListeners.

Joshua Orotayo
fonte
0

Você pode usar esse método para verificar se uma exibição tem filhos ou não.

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

Meu caso foi diferente, a visão filho já tinha uma visão pai. Estou adicionando a visão filho dentro da visão pai a um pai diferente. código de exemplo abaixo

<?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 eu estava inflando essa visualização e adicionando a outro LinearLayout, depois removi o LinaarLayout do layout acima e ele começou a funcionar

o código abaixo corrigiu o 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
fonte
0

Meu problema está relacionado a muitas das outras respostas, mas um motivo um pouco diferente para a necessidade de fazer a alteração ... Eu estava tentando converter uma atividade em um fragmento. Então, mudei o código inflado de onCreate para onCreateView, mas esqueci de converter de setContentView para o método inflate, e a mesma IllegalStateException me levou a esta página.

Eu mudei isso:

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

para isso:

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

Isso resolveu o problema.

Daniel Gibby
fonte