web-dev-qa-db-fra.com

Erreur lors de la décomposition du fragment de classe - ID en double/Illégalargumentexception?

J'essaie de créer une application que je suis en train de construire. Prenons un terme de recherche de l'activité principale, renvoie les résultats, puis clique sur les résultats pour pouvoir afficher un détail de chaque résultat. Je le fais en utilisant un MainActivity, un ResultsActivity et un PlaceActivity, puis un ListFragmentClickable (qui étend ListFragment). Si le combiné est orienté en mode portrait, la liste des résultats doit pouvoir être visualisée, les détails ne pouvant être visualisés que si un résultat est cliqué. Si le combiné est en mode paysage, une fenêtre de détail devrait apparaître à la droite de la liste lorsqu'un élément est sélectionné.

Au moment de l'exécution, j'obtiens une erreur qui se lit comme suit: "Erreur lors de l'inflation d'un fragment de classe". Je n'ai aucune idée de ce qui le cause et j'aimerais beaucoup pouvoir l'aider à s'en débarrasser.

Mes ListFragmentClickables sont appelées par ResultsActivity, qui se trouve ici:

public class ResultsActivity extends FragmentActivity implements ListFragmentClickable.OnItemSelectedListener{

private ArrayAdapter<String> mAdapter;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_results_view);

    //Receive searchTerm from MainActivity
    Intent intent = getIntent();
    String searchTerm = intent.getStringExtra(MainActivity.SEARCH_TERM);

    mAdapter = new ArrayAdapter<String>(this, R.layout.item_label_list);

    FragmentManager     fm = getSupportFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();

    FactualResponderFragment responder = (FactualResponderFragment) fm.findFragmentByTag("RESTResponder");
    if (responder == null) {
        responder = new FactualResponderFragment();
        ft.add(responder, "RESTResponder");
    }

    Bundle bundle = new Bundle();
    bundle.putString("search_term", searchTerm);
    responder.setArguments(bundle);

    ft.commit();
}

public ArrayAdapter<String> getArrayAdapter() {
    return mAdapter;
}

@Override //creates a DetailFragment when a list item is selected
public void onItemSelected(String link) {
    DetailFragment fragment = (DetailFragment) getSupportFragmentManager().findFragmentById(R.id.detailFragment);
    if (fragment != null && fragment.isInLayout()) {
          fragment.setText(link);
    } else {
      Intent intent = new Intent(getApplicationContext(), PlaceActivity.class);
          intent.putExtra(PlaceActivity.EXTRA_URL, link);
      startActivity(intent);
    }
}

}

Voici la classe ListFragmentClickable:

public class ListFragmentClickable extends ListFragment{

  private OnItemSelectedListener listener;


  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
      View view = inflater.inflate(R.layout.activity_results_view, container, false);
      return view;
  }

  @Override
      public void onListItemClick(ListView l, View v, int position, long id) {
          updateDetail(); //see bottom
      }

  public interface OnItemSelectedListener {
      public void onItemSelected(String link);
  }

  @Override
  public void onAttach(Activity activity) {
      super.onAttach(activity);
      if (activity instanceof OnItemSelectedListener) {
          listener = (OnItemSelectedListener) activity;
      } else {
          throw new ClassCastException(activity.toString()
            + " must implemenet ListFragmentClickable.OnItemSelectedListener");
      }
  }


 public void updateDetail() {
        // Create fake data
    String newTime = String.valueOf(System.currentTimeMillis());
    // Send data to Activity
    listener.onItemSelected(newTime); //should direct PlaceActivity!!
  }
}

Voici mon fichier de présentation pour ResultsActivity (activity_results_activity.xml):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:orientation="horizontal" >

<fragment
    Android:id="@+id/fragment_content"
    Android:layout_width="0dp"
    Android:layout_weight="1"
    Android:layout_height="match_parent"
    Android:layout_marginTop="?android:attr/actionBarSize"
    class="com.example.blobtag2.ListFragmentClickable" ></fragment>


<ListView
    Android:id="@Android:id/list"
    Android:layout_width="fill_parent"
    Android:layout_height="50dp"
    Android:divider="#b5b5b5"
    Android:dividerHeight="1dp"></ListView>

</LinearLayout> 

Et enfin voici le journal:

03-21 22:32:03.297: E/AndroidRuntime(764): FATAL EXCEPTION: main
03-21 22:32:03.297: E/AndroidRuntime(764): Java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.blobtag2/com.example.blobtag2.ResultsActivity}: Android.view.InflateException: Binary XML file line #7: Error inflating class fragment
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.app.ActivityThread.performLaunchActivity(ActivityThread.Java:2059)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.app.ActivityThread.handleLaunchActivity(ActivityThread.Java:2084)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.app.ActivityThread.access$600(ActivityThread.Java:130)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1195)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.os.Handler.dispatchMessage(Handler.Java:99)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.os.Looper.loop(Looper.Java:137)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.app.ActivityThread.main(ActivityThread.Java:4745)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Java.lang.reflect.Method.invokeNative(Native Method)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Java.lang.reflect.Method.invoke(Method.Java:511)
03-21 22:32:03.297: E/AndroidRuntime(764):  at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:786)
03-21 22:32:03.297: E/AndroidRuntime(764):  at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:553)
03-21 22:32:03.297: E/AndroidRuntime(764):  at dalvik.system.NativeStart.main(Native Method)
03-21 22:32:03.297: E/AndroidRuntime(764): Caused by: Android.view.InflateException: Binary XML file line #7: Error inflating class fragment
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.view.LayoutInflater.createViewFromTag(LayoutInflater.Java:704)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.view.LayoutInflater.rInflate(LayoutInflater.Java:746)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.view.LayoutInflater.inflate(LayoutInflater.Java:489)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.view.LayoutInflater.inflate(LayoutInflater.Java:396)
03-21 22:32:03.297: E/AndroidRuntime(764):  at com.example.blobtag2.ListFragmentClickable.onCreateView(ListFragmentClickable.Java:32)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:846)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:1061)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.Java:1160)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.Java:272)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.view.LayoutInflater.createViewFromTag(LayoutInflater.Java:676)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.view.LayoutInflater.rInflate(LayoutInflater.Java:746)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.view.LayoutInflater.inflate(LayoutInflater.Java:489)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.view.LayoutInflater.inflate(LayoutInflater.Java:396)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.view.LayoutInflater.inflate(LayoutInflater.Java:352)
03-21 22:32:03.297: E/AndroidRuntime(764):  at com.Android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.Java:256)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.app.Activity.setContentView(Activity.Java:1867)
03-21 22:32:03.297: E/AndroidRuntime(764):  at com.example.blobtag2.ResultsActivity.onCreate(ResultsActivity.Java:37)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.app.Activity.performCreate(Activity.Java:5008)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.app.Instrumentation.callActivityOnCreate(Instrumentation.Java:1079)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.app.ActivityThread.performLaunchActivity(ActivityThread.Java:2023)
03-21 22:32:03.297: E/AndroidRuntime(764):  ... 11 more
03-21 22:32:03.297: E/AndroidRuntime(764): Caused by: Java.lang.IllegalArgumentException: Binary XML file line #7: Duplicate id 0x7f070003, tag null, or parent id 0x0 with another fragment for com.example.blobtag2.ListFragmentClickable
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.Java:277)
03-21 22:32:03.297: E/AndroidRuntime(764):  at Android.view.LayoutInflater.createViewFromTag(LayoutInflater.Java:676)
03-21 22:32:03.297: E/AndroidRuntime(764):  ... 30 more

Toute aide est grandement appréciée. S'il vous plaît laissez-moi savoir s'il y a quelque chose que je peux ajouter?

26
user2163853

Le problème est que le fragment sur xml est chargé deux fois, et la deuxième fois qu'il est ajouté au FragmentManager, vous obtenez une exception IllegalArgumentException. J'ai eu le même problème hier.

Ma solution, je le change pour recréer le fragment de manière dynamique au lieu de le définir sur le fichier xml:

Changer cette partie du fichier xml:

<fragment
    Android:id="@+id/fragment_content"
    Android:layout_width="0dp"
    Android:layout_weight="1"
    Android:layout_height="match_parent"
    Android:layout_marginTop="?android:attr/actionBarSize"
    class="com.example.blobtag2.ListFragmentClickable" ></fragment>

Pour cela à la place:

<FrameLayout
    Android:id="@+id/fragment_content"
    Android:layout_width="0dp"
    Android:layout_weight="1"
    Android:layout_height="match_parent"
    Android:layout_marginTop="?android:attr/actionBarSize" />

Ensuite, dans onCreate, vous devriez remplacer FrameLayout pour un nouveau fragment:

Fragment fragment = new ListFragmentClickable();
FragmentManager     fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragment_content, fragment);
ft.commit(); 

Et puis vous avez la même chose, mais vous ne recevrez pas d’erreur ID dupliqué.

38
Zhen

Cela se produit lorsque des fragments sont définis en XML (de manière statique): FragmentManager ne gère pas les fragments enfants si le fragment parent est détruit. Ensuite, il se brise (erreur "duplicate id") lorsque le code XML est gonflé pour la deuxième fois.

Je contourne ce problème en supprimant le fragment XML manuellement lorsque le parent est détruit , avec ce code dans le fragment parent:

@Override
public void onDestroyView() {

    FragmentManager fm = getFragmentManager();

    Fragment xmlFragment = fm.findFragmentById(R.id.XML_FRAGMENT_ID);
    if (xmlFragment != null) {
        fm.beginTransaction().remove(xmlFragment).commit();
    }

    super.onDestroyView();
}

Note pour copypasters: XML_FRAGMENT_ID est l'id du fragment dans le XML;)


De plus, je préfère une nouvelle classe qui encapsule des fragments XML . Cela simplifie le code puisqu'il ne vous reste plus qu'à étendre votre classe de fragments. Ajoutez cette classe à votre projet:

package net.treboada.mytests.fragments;

import Android.app.Activity;
import Android.os.Bundle;
import Android.support.v4.app.Fragment;
import Android.support.v4.app.FragmentManager;
import Android.util.AttributeSet;

public class XmlFragment extends Fragment {

    @Override
    public void onInflate(Activity activity, AttributeSet attrs,
            Bundle savedInstanceState) {

        FragmentManager fm = getFragmentManager();
        if (fm != null) {
            fm.beginTransaction().remove(this).commit();
        }

        super.onInflate(activity, attrs, savedInstanceState);
    }
}

Ensuite, étendez vos classes de fragments XML:

package net.treboada.mytests.fragments;

public class TestXmlFragment01 extends XmlFragment {

    // ...

}

et voilà! :)

35
caligari

Essayons ceci ... J'ai le même problème et j'ai résolu mon problème en utilisant ce code.

 View root;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    if (root!= null) {
        ViewGroup parent = (ViewGroup) root.getParent();
        if (parent != null)
            parent.removeView(root);
    }
    try {
        root= inflater.inflate(R.layout.map_layout, container, false);
    } catch (InflateException e) {
        /* map is already there, just return view as it is */
    }
    return root;
}
10
RayChongJH

Vous pouvez étendre votre fragment (que vous chargez au format xml) à partir de XmlFragment. Il gère le FragmentManager parent et se supprime.

public class XmlFragment extends BaseFragment {

    @Override
    public void onDestroyView() {
        Fragment parentFragment = getParentFragment();
        FragmentManager manager;
        if (parentFragment != null) {
            // If parent is another fragment, then this fragment is nested
            manager = parentFragment.getChildFragmentManager();
        } else {
            // This fragment is placed into activity
            manager = getActivity().getSupportFragmentManager();
        }
        manager.beginTransaction().remove(this).commitAllowingStateLoss();
        super.onDestroyView();
    }
}
2
Oleksandr

Si vous lisiez les autres réponses ici comme si elles semblaient correctes, regardez ici https://stackoverflow.com/a/19815266/1139784 car elles font référence à la documentation expliquant comment cela n'est pas pris en charge , il est difficile de dire à partir de cette question si l'imbrication de fragments de mise en page est en cours)

Note: You cannot inflate a layout into a fragment when that layout includes a <fragment>.
Nested fragments are only supported when added to a fragment dynamically.

Plus de données ici La meilleure pratique pour les fragments imbriqués dans Android 4.0, 4.1 (<4.2) sans utiliser la bibliothèque de support

Edition: si vous envisagez d'utiliser des fragments imbriqués et que vous n'avez pas besoin de la gestion du cycle de vie, vous pouvez créer un groupe de vues personnalisé (comme l'extension de LinearLayout). http://www.vogella.com/tutorials/AndroidCustomViews/article.html

2
Eric Woodruff

J'ai eu le même problème avec fragment appelé deux fois et la deuxième fois, il s'est écrasé. La solution consiste à implémenter l'instruction remove dans la méthode onDetach:

    @override
public void onDetach(){
super.onDetach();
FragmentManager fm = getFragmentManager()

Fragment xmlFragment = fm.findFragmentById(R.id.yourfragmentid);
if(xmlFragment != null){
    fm.beginTransaction().remove(xmlFragment).commit();
    }
}
0
Helix.Algorithm

Cette ligne

03-21 22:32:03.297: E/AndroidRuntime(764): Caused by: Java.lang.IllegalArgumentException: Binary XML file line #7: Duplicate id 0x7f070003, tag null, or parent id 0x0 with another fragment for com.example.blobtag2.ListFragmentClickable

spécifiquement la partie à la fin

Duplicate id 0x7f070003, tag null, or parent id 0x0 with another fragment for com.example.blobtag2.ListFragmentClickable

vous dit qu’à un moment de la vie de votre activité, vous essayez de créer une vue pour ListFragmentClickable, quand elle existe déjà. Vous devez comprendre comment cela se produit. 

0
j__m