J'ai une application avec trois onglets.
Chaque onglet a son propre fichier de mise en page .xml. Le fichier main.xml possède son propre fragment de carte. C'est celui qui apparaît lors du premier lancement de l'application.
Tout fonctionne bien sauf quand je change entre les onglets. Si j'essaie de revenir à l'onglet de fragment de carte, j'obtiens cette erreur. Passer à et entre d'autres onglets fonctionne très bien.
Qu'est-ce qui pourrait mal ici?
Ceci est ma classe principale et mon main.xml, ainsi qu'une classe pertinente que j'utilise (vous trouverez également le journal des erreurs en bas)
classe principale
package com.nfc.demo;
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.widget.Toast;
public class NFCDemoActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
bar.addTab(bar
.newTab()
.setText("Map")
.setTabListener(
new TabListener<MapFragment>(this, "map",
MapFragment.class)));
bar.addTab(bar
.newTab()
.setText("Settings")
.setTabListener(
new TabListener<SettingsFragment>(this, "settings",
SettingsFragment.class)));
bar.addTab(bar
.newTab()
.setText("About")
.setTabListener(
new TabListener<AboutFragment>(this, "about",
AboutFragment.class)));
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
// setContentView(R.layout.main);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}
public static class TabListener<T extends Fragment> implements
ActionBar.TabListener {
private final Activity mActivity;
private final String mTag;
private final Class<T> mClass;
private final Bundle mArgs;
private Fragment mFragment;
public TabListener(Activity activity, String tag, Class<T> clz) {
this(activity, tag, clz, null);
}
public TabListener(Activity activity, String tag, Class<T> clz,
Bundle args) {
mActivity = activity;
mTag = tag;
mClass = clz;
mArgs = args;
// Check to see if we already have a fragment for this tab,
// probably from a previously saved state. If so, deactivate
// it, because our initial state is that a tab isn't shown.
mFragment = mActivity.getFragmentManager().findFragmentByTag(mTag);
if (mFragment != null && !mFragment.isDetached()) {
FragmentTransaction ft = mActivity.getFragmentManager()
.beginTransaction();
ft.detach(mFragment);
ft.commit();
}
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (mFragment == null) {
mFragment = Fragment.instantiate(mActivity, mClass.getName(),
mArgs);
ft.add(android.R.id.content, mFragment, mTag);
} else {
ft.attach(mFragment);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
ft.detach(mFragment);
}
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
Toast.makeText(mActivity, "Reselected!", Toast.LENGTH_SHORT)
.show();
}
}
}
main.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="vertical" >
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mapFragment"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
classe appropriée (MapFragment.java)
package com.nfc.demo;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MapFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
return inflater.inflate(R.layout.main, container, false);
}
public void onDestroy() {
super.onDestroy();
}
}
Erreur
android.view.InflateException: Binary XML file line #7:
Error inflating class fragment
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
at com.nfc.demo.MapFragment.onCreateView(MapFragment.java:15)
at android.app.Fragment.performCreateView(Fragment.java:1695)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:885)
at android.app.FragmentManagerImpl.attachFragment(FragmentManager.java:1255)
at android.app.BackStackRecord.run(BackStackRecord.java:672)
at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1435)
at android.app.FragmentManagerImpl$1.run(FragmentManager.java:441)
at android.os.Handler.handleCallback(Handler.java:725)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5039)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalArgumentException:
Binary XML file line #7: Duplicate id 0x7f040005, tag null, or
parent id 0xffffffff with another fragment for
com.google.android.gms.maps.MapFragment
at android.app.Activity.onCreateView(Activity.java:4722)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:680)
... 19 more
Réponses:
La réponse de Matt suggère des travaux, mais cela provoque la recréation et le redessin de la carte, ce qui n'est pas toujours souhaitable. Après de nombreux essais et erreurs, j'ai trouvé une solution qui fonctionne pour moi:
Pour faire bonne mesure, voici "map.xml" (R.layout.map) avec R.id.mapFragment (android: id = "@ + id / mapFragment"):
J'espère que cela aide, mais je ne peux pas garantir qu'il n'a pas d'effets négatifs.
Modifier: il y a eu des effets indésirables, comme lors de la fermeture et du redémarrage de l'application. Étant donné que l'application n'est pas nécessairement complètement fermée (mais simplement mise en veille), le code précédent que j'ai soumis échouait au redémarrage de l'application. J'ai mis à jour le code pour quelque chose qui fonctionne pour moi, à la fois entrer et sortir de la carte et quitter et redémarrer l'application, je ne suis pas trop satisfait du bit try-catch, mais il semble fonctionner assez bien.
En regardant la trace de la pile, il m'est venu à l'esprit que je pouvais simplement vérifier si le fragment de carte est dans le FragmentManager, pas besoin du bloc try-catch, code mis à jour.Plus de modifications: il s'avère que vous avez besoin de cet essai après tout. Le simple fait de vérifier le fragment de la carte s'est avéré ne pas fonctionner si bien après tout. Blergh.
la source
SupportMapFragment
inonDestroyView
.Le problème est que ce que vous essayez de faire ne doit pas être fait. Vous ne devriez pas gonfler des fragments à l'intérieur d'autres fragments. De la documentation d'Android :
Bien que vous puissiez être en mesure d'accomplir la tâche avec les hacks présentés ici, je vous suggère fortement de ne pas le faire. Il est impossible d'être sûr que ces hacks géreront ce que fait chaque nouveau système d'exploitation Android lorsque vous essayez de gonfler une disposition pour un fragment contenant un autre fragment.
La seule façon prise en charge par Android pour ajouter un fragment à un autre fragment est via une transaction à partir du gestionnaire de fragments enfants.
Changez simplement votre disposition XML dans un conteneur vide (ajoutez un ID si nécessaire):
Puis dans la
onViewCreated(View view, @Nullable Bundle savedInstanceState)
méthode Fragment :la source
4.3
lors de l'utilisation d'unSupportMapFragment
défini en XML. La création dynamique du fragment et son injection dans une vue de conteneur ont résolu le problème. Voir cette réponse SO .SupportMapFragment.newInstance();
developers.google.com/maps/documentation/android-api/mapJ'ai eu le même problème et j'ai pu le résoudre en supprimant manuellement le
MapFragment
dans laonDestroy()
méthode de laFragment
classe. Voici le code qui fonctionne et fait référence à l'MapFragment
ID par dans le XML:Si vous ne supprimez pas
MapFragment
manuellement, il restera en place de sorte qu'il ne coûte pas beaucoup de ressources pour recréer / afficher à nouveau la vue de la carte. Il semble que conserver le sousMapView
- jacent soit idéal pour basculer entre les onglets, mais lorsqu'il est utilisé dans des fragments, ce comportement provoque laMapView
création d' un doublon à chaque nouveauMapFragment
avec le même ID. La solution consiste à supprimer manuellement leMapFragment
et donc à recréer la carte sous-jacente à chaque fois que le fragment est gonflé.J'ai également noté cela dans une autre réponse [ 1 ].
la source
Voici ma réponse:
1, créez un xml de mise en page comme suit:
2, dans la classe Fragment, ajoutez une carte Google par programmation.
la source
mMapFragment.getMap();
retournenull
. Une idée pourquoi?Ma solution:
la source
Déclarer globalement l'objet SupportMapFragment
Dans la méthode onCreateView (), mettre sous le code
Dans onDestroyView () mettre en dessous du code
Dans votre fichier xml mettez le code ci-dessous
Le code ci-dessus a résolu mon problème et cela fonctionne bien
la source
Je recommanderais
replace()
plutôt queattach()
/detach()
dans votre gestion des onglets.Ou passez à
ViewPager
. Voici un exemple de projet montrant unViewPager
, avec des onglets, hébergeant 10 cartes.la source
Une autre solution:
Ça y est, sinon null vous n'avez pas besoin de le réinitialiser, la suppression du parent est une étape inutile.
la source
J'ai perdu des heures aujourd'hui pour trouver la raison, heureusement, ce problème n'est pas dû à l'implémentation de MapFragment, malheureusement, cela ne fonctionne pas car les fragments imbriqués ne sont pris en charge que via la bibliothèque de support à partir de la version 11.
Mon implémentation a une activité avec barre d'action (en mode onglet) avec deux onglets (pas de viewpager), l'un ayant la carte et l'autre ayant une liste d'entrées. Bien sûr, j'ai été assez naïf pour utiliser MapFragment dans mes fragments d'onglet, et voila l'application s'est écrasée à chaque fois que je revenais sur map-tab.
(Le même problème que j'aurais également au cas où mon fragment de tabulation gonflerait toute disposition contenant un autre fragment).
Une option consiste à utiliser MapView (au lieu de MapFragment), avec quelques frais généraux cependant (voir les documents MapView comme remplacement de remplacement dans le layout.xml, une autre option consiste à utiliser la bibliothèque de support à partir de la version 11, mais ensuite à adopter une approche programmatique puisque les fragments imbriqués ne sont ni pris en charge via la mise en page. Ou tout simplement contourner par programmation en détruisant explicitement le fragment (comme dans la réponse de Matt / Vidar), btw: le même effet est obtenu en utilisant MapView (option 1).
Mais en fait, je ne voulais pas perdre la carte chaque fois que je tabule, c'est-à-dire que je voulais la garder en mémoire et nettoyer uniquement lors de la fermeture de l'activité, j'ai donc décidé de simplement masquer / afficher la carte pendant la tabulation, voir FragmentTransaction / hide
la source
Pour ceux qui rencontrent toujours ce problème, la meilleure façon de vous assurer de ne pas obtenir cette erreur avec une carte dans un onglet consiste à étendre le fragment
SupportMapFragment
au lieu d'imbriquer unSupportMapFragment
à l'intérieur du fragment utilisé pour l'onglet.Je viens de faire fonctionner cela en utilisant un
ViewPager
avec unFragmentPagerAdapter
, avec le SupportMapFragment dans le troisième onglet.Voici la structure générale, notez qu'il n'est pas nécessaire de remplacer la
onCreateView()
méthode, et il n'est pas nécessaire de gonfler le XML de mise en page:Résultat:
Voici le code de classe complet que j'ai utilisé pour tester, qui comprend le fragment d'espace réservé utilisé pour les deux premiers onglets et le fragment de carte utilisé pour le troisième onglet:
la source
Je respecte toutes les réponses mais j'ai trouvé cette solution de liner: Si n est le nombre d'onglets alors:
Exemple: Dans le cas mentionné:
Le pager de vue implémente une file d'attente, vous n'avez donc pas à le laisser supprimer ce fragment. onCreateView n'est appelé qu'une seule fois.
la source
Vous retournez ou gonflez la disposition deux fois, vérifiez simplement si vous ne gonflez qu'une seule fois.
la source
Les fragments imbriqués ne sont actuellement pas pris en charge. Essayez le Support Package, révision 11 .
la source
Avez-vous essayé de référencer votre
MapFragment
classe personnalisée dans le fichier de disposition?la source
Si vous n'utilisez que la réponse Vidar Wahlberg, vous obtenez une erreur lorsque vous ouvrez une autre activité (par exemple) et revenez à la carte. Ou dans mon cas, ouvrez une autre activité, puis à partir d'une nouvelle activité, ouvrez à nouveau la carte (sans utiliser le bouton de retour). Mais lorsque vous combinez la solution Vidar Wahlberg et la solution Matt, vous n'aurez pas d'exceptions.
disposition
Fragment
la source
Je l'avais dans viewPager et le crash était dû au fait que tout fragment devait avoir sa propre balise, les balises en double ou les identifiants pour le même fragment ne sont pas autorisés.
la source
Je pense qu'il y avait quelques bugs dans la bibliothèque App-Compat précédente pour Fragment enfant. J'ai essayé @Vidar Wahlberg et @ Matt's et ils ne fonctionnaient pas pour moi. Après avoir mis à jour la bibliothèque appcompat, mon code fonctionne parfaitement sans effort supplémentaire.
la source
Ce qu'il faut noter ici, c'est que votre application plantera gravement dans l'un des deux cas suivants: -
Voici un exemple d'extrait de code pour une utilisation correcte de MapView
XML
Le résultat ressemble à ceci: -
J'espère que cela aidera quelqu'un.
la source
Dans cette solution, vous n'avez pas besoin de prendre de variable statique;
la source
Je suis un peu en retard à la fête mais aucune de ces réponses ne m'a aidé dans mon cas. J'utilisais Google map comme SupportMapFragment et PlaceAutocompleteFragment dans mon fragment. Comme toutes les réponses ont souligné le fait que le problème est que SupportMapFragment est la carte à recréer et à redessiner, mais après avoir creusé, mon problème était en fait avec PlaceAutocompleteFragment
Voici donc la solution de travail pour ceux qui sont confrontés à ce problème en raison de SupportMapFragment et SupportMapFragment
Et dans onDestroyView, effacez SupportMapFragment et SupportMapFragment
la source
Essayez de définir un identifiant (android: id = "@ + id / maps_dialog") pour la disposition parent mapView. Travaille pour moi.
la source
Quiconque vient ici maintenant qui obtient ce type d'erreur lors de l'ouverture de l'un
Dialog
ou l'autreFragment
avec Google PlacesAutocompleteSupportFragment
, essayez ce one-liner (je ne sais pas à quel point c'est sûr mais cela fonctionne pour moi):autocompleteFragment.getFragmentManager().beginTransaction().remove(autocompleteFragment).commit();
avant de rejeter / détruire votre fragment.
la source
Pourquoi n'insérez-vous pas une carte à l'aide de l'objet MapView au lieu de MapFragment? Je ne sais pas s'il y a une limitation dans MapView, bien que je l'ai trouvée utile.
la source