java.lang.IllegalStateException: O filho especificado já tem um pai

99

Estou usando fragmentos, quando instanciarei um fragmento pela primeira vez. mas na segunda vez recebi essa exceção. Não consegui encontrar a linha onde encontrei o erro.

 04-04 08:51:54.320: E/AndroidRuntime(29713): FATAL EXCEPTION: main
    04-04 08:51:54.320: E/AndroidRuntime(29713): java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at android.view.ViewGroup.addViewInner(ViewGroup.java:3013)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at android.view.ViewGroup.addView(ViewGroup.java:2902)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at android.view.ViewGroup.addView(ViewGroup.java:2859)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at android.view.ViewGroup.addView(ViewGroup.java:2839)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at android.support.v4.app.NoSaveStateFrameLayout.wrap(Unknown Source)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at android.support.v4.app.FragmentManagerImpl.moveToState(Unknown Source)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at android.support.v4.app.FragmentManagerImpl.moveToState(Unknown Source)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at android.support.v4.app.BackStackRecord.run(Unknown Source)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at android.support.v4.app.FragmentManagerImpl.execPendingActions(Unknown Source)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at android.support.v4.app.FragmentManagerImpl$1.run(Unknown Source)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at android.os.Handler.handleCallback(Handler.java:587)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at android.os.Handler.dispatchMessage(Handler.java:92)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at android.os.Looper.loop(Looper.java:132)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at android.app.ActivityThread.main(ActivityThread.java:4126)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at java.lang.reflect.Method.invokeNative(Native Method)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at java.lang.reflect.Method.invoke(Method.java:491)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
    04-04 08:51:54.320: E/AndroidRuntime(29713):    at dalvik.system.NativeStart.main(Native Method)

Aqui estão o que eu faço quando clico em um elemento do fragmento da minha lista.

// If we are not currently showing a fragment for the new
 // position, we need to create and install a new one.
 RouteSearchFragment df = RouteSearchFragment.newInstance(index);

 // Execute a transaction, replacing any existing fragment
 // with this one inside the frame.
 FragmentTransaction ft = fragmentManager.beginTransaction();
 ft.replace(R.id.details_full, df);
 ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
 ft.commit();

A primeira vez que está tudo bem, clico em element2 da lista, também está ok; mas quando eu volto para element1 eu tenho esse bug.

Obrigado a todos!

Haythem Souissi
fonte
precisa chamar layoutView.removeAllViews (); antes de adicionar visualizações ao layout
ρяσѕρєя K
@imrankhan errado! Você pode adicionar sem remover tudo. A parte mais importante está faltando e como não há pacote personalizado no stacktrace, sugiro que você remova algum código e teste-o passo a passo ...
WarrenFaith
1
eu adicionei mais detalhes, por favor, você pode ver isso?
haythem souissi
O que é essa classe RouteSearchFragment ?? Não consigo encontrar nenhuma referência nos documentos do Android. Atualize a definição da classe também.
noob

Respostas:

36

Quando você substitui OnCreateViewem sua RouteSearchFragmentclasse, você tem o

if(view != null) {
    return view; 
}

segmento de código?

Nesse caso, remover a instrução de retorno deve resolver seu problema.

Você pode manter o código e retornar a visualização se não quiser regenerar os dados da visualização, e o método onDestroyView () você remove esta visualização de seu pai assim:

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        if (view != null) {
            ViewGroup parent = (ViewGroup) view.getParent();
            if (parent != null) {
                parent.removeAllViews();
            }
        }
    }
Medo
fonte
5
@Override public void onDestroyView () {super.onDestroyView (); ViewGroup parentViewGroup = (ViewGroup) mRoutesSearchViewContainer.getParent (); if (null! = parentViewGroup) {parentViewGroup.removeView (mRoutesSearchViewContainer); }}
haythem souissi
@Medo: Você pode dar uma breve explicação para isso. Tenho o mesmo erro mostrado no logcat. como você deu a sugestão "remover a instrução de retorno deve resolver seu problema", mas precisamos retornar o objeto View no método onCreateView (). você pode fornecer um código de snippet para sua explicação. Obrigado.
Krishna Prasad
@Krishna Basta inflar e retornar a visualização como faria normalmente. Você pode pular toda a instrução if.
Medo
65
Para mim, eu só tive que substituir return inflater.inflate(R.layout.fragment_search, container);porreturn inflater.inflate(R.layout.fragment_search, container, false);
Sufian
370

Desculpe postar uma pergunta antiga, mas consegui corrigi-la usando uma solução totalmente diferente. Eu estava recebendo essa exceção, mas mudei a primeira linha da minha substituição onCreatView:

View result = inflater.inflate(R.layout.customer_layout, container);

...para isso:

View result = inflater.inflate(R.layout.customer_layout, container, false);

Não tenho ideia do porquê, mas usar a substituição que aceita o booleano como o terceiro parâmetro corrigiu. Acho que diz ao Fragment e / ou Activity para não usar o "container" como o pai da View recém-criada.

Patrick
fonte
53
Não se desculpe - isso foi muito útil para mim e, obviamente, para várias outras pessoas. Obrigado!
entre nos códigos de
Muito obrigado, continuo esquecendo isso e voltando a esta resposta
noloman
@Patrick, o primeiro anexa a visão inflada ao contêiner, adicionando o sinalizador falso especifica que você não deseja adicionar a visão inflada ao contêiner.
Ne0 de
e eu continuo voltando a este post e descobrindo que esta é A RESPOSTA :)
noloman
45

Eu tenho enfrentado esse problema muitas vezes. Adicione o seguinte código para resolver este problema:

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

obrigado

Hardik
fonte
Obrigado por esta solução :) Tenho um caso muito específico onde não posso usar o inflater para resolver isso. Você me economizou muito tempo
Bojan
Desculpe, não entendo muito bem porque sou novo no Android.
Zin Win Htet
Em view.getParent (); De onde vem o objeto de visualização de dose?
Zin Win Htet
Cristy YG: Pegue uma instância de View como uma variável global e aumente seu layout xml na variável global acima. você está me seguindo ou não?
Hardik
Sim, ver a instância declarada como global.
Hardik
35

Se você tem esta declaração ..

View view = inflater.inflate(R.layout.fragment1, container);//may be Incorrect 

Então tente isso .. Adicione false como terceiro argumento .. Pode ser que possa ajudar ..

View view = inflater.inflate(R.layout.fragment1, container, false);//correct one
Dhananjay M
fonte
21

Eu tinha esse código em um fragmento e ele estava travando se eu tentasse voltar a este fragmento

if (mRootView == null) {
    mRootView = inflater.inflate(R.layout.fragment_main, container, false);
} 

depois de reunir as respostas neste tópico, percebi que o pai do mRootView ainda tem mRootView como filho. Então, essa foi a minha solução.

if (mRootView == null) {
    mRootView = inflater.inflate(R.layout.fragment_main, container, false);
} else {
    ((ViewGroup) mRootView.getParent()).removeView(mRootView);
}

espero que isto ajude

user1736525
fonte
2
1 me ajudou. Especialmente verdadeiro se sua atividade permanecer, mas o gerenciador de fragmentos estiver adicionando novos fragmentos no topo. quando ele voltar para o primeiro fragmento, certifique-se de que a visão do root antigo seja removida. Obrigado!
Bundeeteddee de
Isto me ajudou bastante. Venho encontrando essa solução há 3 dias. Resposta simples e bonita.
Zin Win Htet
Uau! finalmente funcionou para mim! solução grat. obrigado!
avisper
Eu não tenho um motivo lógico por que "(ViewGroup) mRootView.getParent ()). RemoveView (mRootView);" funciona em contraste com a chamada direta de "<WhateverIsParentViewGroupName> .removeView (mRootView)" Mas isso funciona para mim também, estou testando no Android 8.0 e 9.0. Obrigado amigo ^
Khay
16

Isso também acontece quando a visualização retornada por onCreateView () não é a visualização que foi inflada.

Exemplo:

View rootView = inflater.inflate(R.layout.my_fragment, container, false);

TextView textView = (TextView) rootView.findViewById(R.id.text_view);
textView.setText("Some text.");

return textView;

Consertar:

return rootView;

Ao invés de:

return textView; // or whatever you returned
Mateus Pires
fonte
Obrigado! isso me ajudou!
Sudheesh Mohan
5

Tive esse problema e não consegui resolvê-lo no código Java. O problema era com meu xml.

Eu estava tentando adicionar um textView a um contêiner, mas tinha envolvido o textView dentro de um LinearLayout.

Este era o arquivo xml original:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@android:id/text1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceListItemSmall"
        android:gravity="center_vertical"
        android:paddingLeft="16dp"
        android:paddingRight="16dp"
        android:textColor="#fff"
        android:background="?android:attr/activatedBackgroundIndicator"
        android:minHeight="?android:attr/listPreferredItemHeightSmall"/>

</LinearLayout>

Agora com o LinearLayout removido:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@android:id/text1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceListItemSmall"
        android:gravity="center_vertical"
        android:paddingLeft="16dp"
        android:paddingRight="16dp"
        android:textColor="#fff"
        android:background="?android:attr/activatedBackgroundIndicator"
        android:minHeight="?android:attr/listPreferredItemHeightSmall"/>

Isso não parecia muito para mim, mas funcionou, e eu não mudei meu código Java. Estava tudo no xml.

DroidCrafter
fonte
2

Você está adicionando um Viewem um layout, mas a visualização já está em outro layout. Uma visualização não pode estar em mais de um lugar.

novato
fonte
Eu adicionei mais detalhes à minha pergunta, por favor, você pode ver isso?
haythem souissi
1

Esta solução pode ajudar:

public class FragmentItem extends Android.Support.V4.App.Fragment
{
    View rootView;
    TextView textView;

    public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if (rootView != null) 
        {
            ViewGroup parent = (ViewGroup)rootView.Parent;
            parent.RemoveView(rootView);
        } else {
            rootView = inflater.Inflate(Resource.Layout.FragmentItem, container, false);
            textView = rootView.FindViewById<TextView>(Resource.Id.textViewDisplay);            
        }
        return rootView;
    }
}
Bhavit S. Sengar
fonte
1
Acho que rootView sempre será nulo, pois você não o inicializou.
Zin Win Htet
rootView sempre ser nulo
Thinsky,
1

Eu resolvi, definindo attachToRootde inflater.inflate()a false.

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_overview, container, false);
    return view;
}
Sr. B.
fonte
0

em seu arquivo xml, você deve definir layout_width e layout_height de wrap_content para match_parent. está consertado para mim.

<FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
Evan Ngo
fonte