java.lang.IllegalStateException: l'enfant spécifié a déjà un parent

99

J'utilise des fragments, lorsque j'instancie un fragment la première fois. mais la deuxième fois, j'ai eu cette exception. Je n'ai pas trouvé la ligne où j'ai eu l'erreur?

 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)

Voici ce que je fais lorsque je clique sur un élément de mon fragment de liste.

// 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();

La première fois que c'est OK, je clique sur element2 dans la liste, c'est aussi ok; mais quand je reviens à element1 j'ai eu ce bug.

Merci tout le monde!

haythem souissi
la source
besoin d'appeler layoutView.removeAllViews (); avant d'ajouter des vues à la mise en page
ρяσѕρєя K
@imrankhan mal! Vous pouvez ajouter sans tout supprimer. La partie la plus importante est manquante et comme il n'y a pas de package personnalisé dans le stacktrace, je vous suggère de supprimer du code et de le tester étape par étape ...
WarrenFaith
1
j'ajoute plus de détails, pouvez-vous voir ça?
haythem souissi
Quelle est cette classe RouteSearchFragment ?? Impossible de trouver une référence dans les documents Android. Veuillez également mettre à jour la définition de classe.
noob

Réponses:

36

Lorsque vous remplacez OnCreateViewdans votre RouteSearchFragmentclasse, avez-vous le

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

segment de code?

Si tel est le cas, la suppression de l'instruction return devrait résoudre votre problème.

Vous pouvez conserver le code et retourner la vue si vous ne voulez pas régénérer les données de la vue, et la méthode onDestroyView () vous supprimez cette vue de son parent comme ceci:

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        if (view != null) {
            ViewGroup parent = (ViewGroup) view.getParent();
            if (parent != null) {
                parent.removeAllViews();
            }
        }
    }
Medo
la source
5
@Override public void onDestroyView () {super.onDestroyView (); ViewGroup parentViewGroup = (ViewGroup) mRoutesSearchViewContainer.getParent (); if (null! = parentViewGroup) {parentViewGroup.removeView (mRoutesSearchViewContainer); }}
haythem souissi
@Medo: Pouvez-vous donner une brève explication à ce sujet. J'ai la même erreur indiquée dans le logcat. comme vous avez donné la suggestion "supprimer l'instruction return devrait résoudre votre problème" mais nous devons renvoyer l'objet View dans la méthode onCreateView (). pouvez-vous fournir un extrait de code pour votre explication. Je vous remercie.
Krishna Prasad
@Krishna Il suffit de gonfler et de renvoyer la vue comme vous le feriez normalement. Vous pouvez ignorer toute l'instruction if.
Medo
65
Pour moi, je devais juste remplacer return inflater.inflate(R.layout.fragment_search, container);parreturn inflater.inflate(R.layout.fragment_search, container, false);
Sufian
370

Désolé de publier une ancienne question, mais j'ai pu la résoudre en utilisant une solution totalement différente. J'obtenais cette exception mais j'ai changé la première ligne de mon remplacement onCreatView à partir de ceci:

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

...pour ça:

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

Je n'ai aucune idée de pourquoi, mais en utilisant le remplacement qui accepte le booléen comme troisième paramètre le fixe. Je pense que cela indique au fragment et / ou à l'activité de ne pas utiliser le "conteneur" comme parent de la vue nouvellement créée.

Patrick
la source
53
Ne soyez pas désolé - cela a été très utile pour moi, et clairement pour un certain nombre d'autres personnes. Merci!
tête dans les codes
Merci beaucoup, je continue d'oublier cela et de revenir à cette réponse
noloman
@Patrick, Le premier attache la vue gonflée au conteneur, l'ajout de l'indicateur false spécifie que vous ne voulez pas ajouter la vue gonflée au conteneur.
Ne0
et je reviens sans
cesse
45

J'ai fait face à ce problème à plusieurs reprises. Veuillez ajouter le code suivant pour résoudre ce problème:

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

Merci

Hardik
la source
Merci pour cette solution :) J'ai un cas très particulier où je ne peux pas utiliser gonfleur pour résoudre ce problème. Vous m'avez sauvé beaucoup de temps
Bojan
Je suis désolé, je ne comprends pas très bien car je suis nouveau sur Android.
Zin Win Htet
In view.getParent (); D'où vient l'objet de vue de dose?
Zin Win Htet
Cristy YG: prenez une instance de View comme variable globale et gonflez votre mise en page XML sur la variable globale ci-dessus. tu me suis ou pas?
Hardik
Oui, affichez l'instance déclarée comme globale.
Hardik
35

Si vous avez cette déclaration ...

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

Ensuite, essayez ceci. Ajoutez false comme troisième argument. Cela pourrait peut-être vous aider.

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

J'avais ce code dans un fragment et il plantait si j'essaye de revenir sur ce fragment

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

après avoir rassemblé les réponses sur ce fil, j'ai réalisé que le parent de mRootView avait toujours mRootView comme enfant. Donc, c'était ma solution.

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

J'espère que cela t'aides

user1736525
la source
2
+1 m'a aidé. Particulièrement vrai si votre activité reste mais que le gestionnaire de fragments ajoute de nouveaux fragments par-dessus. quand il revient au premier fragment, vous devez vous assurer que l'ancienne vue racine est supprimée. Merci!
Bundeeteddee
Cela m'a beaucoup aidé. Je trouve cette solution depuis 3 jours. Réponse simple et jolie.
Zin Win Htet
Hou la la! enfin ça a marché pour moi! solution grat. Merci!
avisper
Je n'ai pas de raison pour laquelle "(ViewGroup) mRootView.getParent ()). RemoveView (mRootView);" fonctionne contrairement à appeler directement "<WwhatIsParentViewGroupName> .removeView (mRootView)" Mais cela fonctionne pour moi aussi, je teste sur Android 8.0 et 9.0. Merci bud ^
Khay
16

Cela se produit également lorsque la vue renvoyée par onCreateView () n'est pas la vue qui a été gonflée.

Exemple:

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;

Réparer:

return rootView;

Au lieu de:

return textView; // or whatever you returned
Mateus Pires
la source
Merci! ça m'a aidé!
Sudheesh Mohan
5

J'ai eu ce problème et je n'ai pas pu le résoudre en code Java. Le problème était avec mon xml.

J'essayais d'ajouter un textView à un conteneur, mais j'avais enveloppé le textView dans un LinearLayout.

C'était le fichier xml d'origine:

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

Maintenant avec le LinearLayout supprimé:

<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"/>

Cela ne me semblait pas grand-chose mais cela a fonctionné, et je n'ai pas du tout changé mon code Java. Tout était dans le xml.

DroidCrafter
la source
2

Vous ajoutez un Viewdans un layout, mais la vue est déjà dans une autre layout. Une vue ne peut pas se trouver à plusieurs endroits.

Noob
la source
J'ai ajouté plus de détails à ma question, voyez-vous cela?
haythem souissi
1

Cette solution peut aider:

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
la source
1
Je pense que rootView sera toujours nul puisque vous ne l'avez pas initialisé.
Zin Win Htet
rootView toujours être nul
Thinsky
1

Je l' ai résolu en mettant attachToRootde inflater.inflate()à false.

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

dans votre fichier xml, vous devez définir layout_width et layout_height de wrap_content à match_parent. c'est réglé pour moi.

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