Id. Duplicada, etiqueta nula o identificador padre con otro fragmento para com.google.android.gms.maps.MapFragment

Tengo una aplicación con tres pestañas.

Cada ficha tiene su propio archivo .xml de diseño. El archivo main.xml tiene su propio fragmento de mapa. Es el que aparece cuando la aplicación se lanza por primera vez.

Todo funciona bien, excepto cuando cambio entre pestañas. Si intento volver a la pestaña de fragmentos del mapa, obtengo este error. Cambiar a y entre otras pestañas funciona muy bien.

¿Qué podría estar mal aquí?

Esta es mi clase principal y mi main.xml, así como una clase relevante que uso (también encontrarás el registro de errores en la parte inferior)

clase principal

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> 

Clase relevante (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(); } } 

error

 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 

La respuesta de Matt sugiere obras, pero hace que el mapa sea recreado y rediseñado, lo que no siempre es deseable. Después de muchas pruebas y errores, encontré una solución que funciona para mí:

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

Para una buena medida, aquí está "map.xml" (R.layout.map) con R.id.mapFragment (android: id = "@ + id / mapFragment"):

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mapLayout" android:layout_width="match_parent" android:layout_height="match_parent" > <fragment xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mapFragment" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.SupportMapFragment" /> </LinearLayout> 

Espero que esto ayude, pero no puedo garantizar que no tenga efectos adversos.

Editar: Hubo algunos efectos adversos, como al salir de la aplicación y volver a iniciarla. Dado que la aplicación no está necesariamente completamente cerrada (pero acaba de poner a dormir en segundo plano), el código anterior i enviado fallaría al reiniciar la aplicación. He actualizado el código a algo que funciona para mí, tanto entrar y salir del mapa y salir y reiniciar la aplicación, no estoy muy contento con el try-catch bit, pero parece que funciona lo suficientemente bien. Al mirar el rastro de la pila me ocurrió que podría apenas comprobar si el fragmento del mapa está en el FragmentManager, ninguna necesidad para el bloque del try-catch, código actualizado.

Más ediciones: Resulta que necesita que try-catch después de todo. Sólo comprobar el fragmento del mapa resultó no funcionar tan bien después de todo. Blergh.

El problema es que lo que usted está tratando de hacer no se debe hacer. No debes inflar fragmentos dentro de otros fragmentos. De la documentación de Android:

Nota: No se puede inflar un diseño en un fragmento cuando ese diseño incluye un <fragmento>. Los fragmentos anidados sólo se admiten cuando se añaden dinámicamente a un fragmento.

Mientras que usted puede ser capaz de realizar la tarea con los hacks presentados aquí, le sugiero que no lo haga. Es imposible estar seguro de que estos hacks se encargarán de lo que hace cada nuevo sistema operativo Android cuando intenta inflar un diseño para un fragmento que contiene otro fragmento.

La única forma compatible con Android para agregar un fragmento a otro fragmento es a través de una transacción del gestor de fragmentos secundarios.

Simplemente cambie su diseño XML en un contenedor vacío (agregue un ID si es necesario):

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mapFragmentContainer" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > </LinearLayout> 

A continuación, en el fragmento onViewCreated(View view, @Nullable Bundle savedInstanceState) método:

 @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); FragmentManager fm = getChildFragmentManager(); SupportMapFragment mapFragment = (SupportMapFragment) fm.findFragmentByTag("mapFragment"); if (mapFragment == null) { mapFragment = new SupportMapFragment(); FragmentTransaction ft = fm.beginTransaction(); ft.add(R.id.mapFragmentContainer, mapFragment, "mapFragment"); ft.commit(); fm.executePendingTransactions(); } mapFragment.getMapAsync(callback); } 

Tuve el mismo problema y fue capaz de resolverlo mediante la eliminación manual de MapFragment en el método onDestroy() de la clase Fragment . Aquí está el código que funciona y hace referencia al MapFragment por ID en el XML:

 @Override public void onDestroyView() { super.onDestroyView(); MapFragment f = (MapFragment) getFragmentManager() .findFragmentById(R.id.map); if (f != null) getFragmentManager().beginTransaction().remove(f).commit(); } 

Si no quita el MapFragment manualmente, se quedará colgando para que no cueste muchos recursos para volver a crear / mostrar la vista del mapa. Parece que mantener el MapView subyacente es ideal para cambiar de una parte a otra de las pestañas, pero cuando se usa en fragmentos, este comportamiento hace que se MapView un MapView duplicado en cada nuevo MapFragment con el mismo ID. La solución es quitar manualmente el MapFragment y recrear el mapa subyacente cada vez que se infla el fragmento.

También noté esto en otra respuesta [ 1 ].

Esta es mi respuesta:

1, Crear un diseño xml como sigue:

 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/map_container" android:layout_width="match_parent" android:layout_height="match_parent"> </FrameLayout> 

2, en la clase Fragmento, agregue un mapa de google por programación.

 import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.SupportMapFragment; import android.app.Activity; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; /** * A simple {@link android.support.v4.app.Fragment} subclass. Activities that * contain this fragment must implement the * {@link MapFragment.OnFragmentInteractionListener} interface to handle * interaction events. Use the {@link MapFragment#newInstance} factory method to * create an instance of this fragment. * */ public class MapFragment extends Fragment { // TODO: Rename parameter arguments, choose names that match private GoogleMap mMap; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_map, container, false); SupportMapFragment mMapFragment = SupportMapFragment.newInstance(); mMap = mMapFragment.getMap(); FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); transaction.add(R.id.map_container, mMapFragment).commit(); return view; } @Override public void onAttach(Activity activity) { super.onAttach(activity); Log.d("Attach", "on attach"); } @Override public void onDetach() { super.onDetach(); } } 
  1. Como se mencionó por @Justin Breitfeller, la solución @Vidar Wahlberg es un hack que podría no funcionar en la futura versión de Android.
  2. @Vidar Wahlberg perfer un hack porque otra solución podría "hacer que el mapa sea recreado y rediseñado, lo que no siempre es deseable". El redibujo del mapa se podría prevenir manteniendo el viejo fragmento del mapa, en vez de crear una nueva instancia cada vez.
  3. @Matt solución no funciona para mí (IllegalStateException)
  4. Como se cita por @Justin Breitfeller, "No se puede inflar un diseño en un fragmento cuando ese diseño incluye a. Los fragmentos anidados sólo se admiten cuando se agrega a un fragmento dinámicamente".

Mi solución:

 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_map_list, container, false); // init //mapFragment = (SupportMapFragment)getChildFragmentManager().findFragmentById(R.id.map); // don't recreate fragment everytime ensure last map location/state are maintain if (mapFragment == null) { mapFragment = SupportMapFragment.newInstance(); mapFragment.getMapAsync(this); } FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); // R.id.map is a layout transaction.replace(R.id.map, mapFragment).commit(); return view; } 

Recomendaría replace() lugar de attach() / detach() en su manipulación de la pestaña.

O bien, cambie a ViewPager . Aquí hay un ejemplo de proyecto que muestra un ViewPager , con pestañas, que aloja 10 mapas.

Para aquellos que siguen corriendo este problema, la mejor manera de asegurarse de que no obtiene este error con un mapa en una pestaña es hacer que el fragmento extender SupportMapFragment lugar de anidar un SupportMapFragment dentro del fragmento utilizado para la ficha.

Acabo de conseguir esto trabajando con un ViewPager con un FragmentPagerAdapter , con el SupportMapFragment en la tercera pestaña.

Aquí está la estructura general, nota que no hay necesidad de anular el método onCreateView() , y no hay necesidad de inflar cualquier formato xml:

 public class MapTabFragment extends SupportMapFragment implements OnMapReadyCallback { private GoogleMap mMap; private Marker marker; public MapTabFragment() { } @Override public void onResume() { super.onResume(); setUpMapIfNeeded(); } private void setUpMapIfNeeded() { if (mMap == null) { getMapAsync(this); } } @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; setUpMap(); } private void setUpMap() { mMap.setMyLocationEnabled(true); mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID); mMap.getUiSettings().setMapToolbarEnabled(false); mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() { @Override public void onMapClick(LatLng point) { //remove previously placed Marker if (marker != null) { marker.remove(); } //place marker where user just clicked marker = mMap.addMarker(new MarkerOptions().position(point).title("Marker") .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA))); } }); } } 

Resultado:

Introduzca aquí la descripción de la imagen

Aquí está el código de clase completo que usé para probar, que incluye el marcador de posición Fragmento utilizado para las dos primeras pestañas y el Fragmento de mapa utilizado para la tercera pestaña:

 public class MainActivity extends AppCompatActivity implements ActionBar.TabListener{ SectionsPagerAdapter mSectionsPagerAdapter; ViewPager mViewPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); // Set up the ViewPager with the sections adapter. mViewPager = (ViewPager) findViewById(R.id.pager); mViewPager.setAdapter(mSectionsPagerAdapter); final ActionBar actionBar = getSupportActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { actionBar.setSelectedNavigationItem(position); } }); for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) { actionBar.addTab(actionBar.newTab().setText(mSectionsPagerAdapter.getPageTitle(i)).setTabListener(this)); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } @Override public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) { mViewPager.setCurrentItem(tab.getPosition()); } @Override public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { } @Override public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) { } public class SectionsPagerAdapter extends FragmentPagerAdapter { public SectionsPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { switch (position) { case 0: return PlaceholderFragment.newInstance(position + 1); case 1: return PlaceholderFragment.newInstance(position + 1); case 2: return MapTabFragment.newInstance(position + 1); } return null; } @Override public int getCount() { // Show 3 total pages. return 3; } @Override public CharSequence getPageTitle(int position) { Locale l = Locale.getDefault(); switch (position) { case 0: return getString(R.string.title_section1).toUpperCase(l); case 1: return getString(R.string.title_section2).toUpperCase(l); case 2: return getString(R.string.title_section3).toUpperCase(l); } return null; } } public static class PlaceholderFragment extends Fragment { private static final String ARG_SECTION_NUMBER = "section_number"; TextView text; public static PlaceholderFragment newInstance(int sectionNumber) { PlaceholderFragment fragment = new PlaceholderFragment(); Bundle args = new Bundle(); args.putInt(ARG_SECTION_NUMBER, sectionNumber); fragment.setArguments(args); return fragment; } public PlaceholderFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main, container, false); text = (TextView) rootView.findViewById(R.id.section_label); text.setText("placeholder"); return rootView; } } public static class MapTabFragment extends SupportMapFragment implements OnMapReadyCallback { private static final String ARG_SECTION_NUMBER = "section_number"; private GoogleMap mMap; private Marker marker; public static MapTabFragment newInstance(int sectionNumber) { MapTabFragment fragment = new MapTabFragment(); Bundle args = new Bundle(); args.putInt(ARG_SECTION_NUMBER, sectionNumber); fragment.setArguments(args); return fragment; } public MapTabFragment() { } @Override public void onResume() { super.onResume(); Log.d("MyMap", "onResume"); setUpMapIfNeeded(); } private void setUpMapIfNeeded() { if (mMap == null) { Log.d("MyMap", "setUpMapIfNeeded"); getMapAsync(this); } } @Override public void onMapReady(GoogleMap googleMap) { Log.d("MyMap", "onMapReady"); mMap = googleMap; setUpMap(); } private void setUpMap() { mMap.setMyLocationEnabled(true); mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID); mMap.getUiSettings().setMapToolbarEnabled(false); mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() { @Override public void onMapClick(LatLng point) { Log.d("MyMap", "MapClick"); //remove previously placed Marker if (marker != null) { marker.remove(); } //place marker where user just clicked marker = mMap.addMarker(new MarkerOptions().position(point).title("Marker") .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA))); Log.d("MyMap", "MapClick After Add Marker"); } }); } } } 

Otra solución:

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

Eso es todo, si no es nulo no es necesario reinicializar la eliminación de los padres es un paso innecesario.

He perdido horas hoy para encontrar la razón, afortunadamente este problema no es debido a la implementación de MapFragment, por desgracia, esto no funciona porque los fragmentos anidados sólo se admiten a través de la biblioteca de soporte de rev 11.

Mi implementación tiene una actividad con la barra de acciones (en modo tabulado) con dos pestañas (sin visor), una con el mapa y la otra con una lista de entradas. Por supuesto que he sido bastante ingenuo para usar MapFragment dentro de mis fragmentos de la pestaña, y voila la aplicación se estrelló cada vez que cambié de nuevo a la mapa de la pestaña.

(La misma cuestión que yo también tendría en caso de que mi fragmento de tabulación inflaría cualquier diseño que contenga cualquier otro fragmento).

Una opción es usar MapView (en lugar de MapFragment), con algunos overhead (ver MapView Docs como reemplazo de drop-in en el layout.xml), otra opción es usar la biblioteca de soporte desde rev.11 pero luego tomar el enfoque programático Ya que los fragmentos anidados no son soportados a través del diseño, o simplemente funcionando de forma programática mediante la destrucción explícita del fragmento (como en la respuesta de Matt / Vidar), btw: el mismo efecto se logra utilizando el MapView (opción 1).

Pero en realidad, no quería perder el mapa cada vez que me separaba, es decir, quería mantenerlo en la memoria y la limpieza sólo al cerrar la actividad, así que decidí simplemente ocultar / mostrar el mapa durante la pestaña, vea FragmentTransaction / hide

Respeto todas las respuestas, pero he encontrado esta solución de un forro: Si n es el número de pestañas entonces:

  mViewPager.setOffscreenPageLimit(n); 

Ejemplo: En caso de que se mencione:

  mViewPager.setOffscreenPageLimit(2); 

View pager implementa una cola así, no tienes que dejar que elimine ese fragmento. OnCreateView se llama una sola vez.

Declare el objeto SupportMapFragment globalmente

  private SupportMapFragment mapFragment; 

En el método onCreateView () poner debajo del código

 mapFragment = (SupportMapFragment) getChildFragmentManager() .findFragmentById(R.id.map); mapFragment.getMapAsync(this); 

En onDestroyView () poner debajo del código

 @Override public void onDestroyView() { super.onDestroyView(); if (mapFragment != null) getFragmentManager().beginTransaction().remove(mapFragment).commit(); } 

En su archivo xml poner debajo del código

  <fragment android:id="@+id/map" android:name="com.abc.Driver.fragment.FragmentHome" class="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> 

Por encima del código resuelto mi problema y está funcionando bien

Los fragmentos anidados no se admiten actualmente. Prueba el paquete de soporte, revisión 11 .

¿Ha estado intentando hacer referencia a su clase MapFragment personalizada en el archivo de diseño?

 <?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.nfc.demo.MapFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> 

Si utilizas solo la respuesta de Vidar Wahlberg, obtienes un error al abrir otra actividad (por ejemplo) y volver al mapa. O en mi caso abrir otra actividad y luego de la nueva actividad abrir el mapa de nuevo (sin utilizar el botón de nuevo). Pero cuando se combina la solución Vidar Wahlberg y la solución Matt, no habrá excepciones.

diseño

 <com.example.ui.layout.MapWrapperLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/map_relative_layout"> <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/root"> <fragment xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/map" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.SupportMapFragment" /> </RelativeLayout> </<com.example.ui.layout.MapWrapperLayout> 

Fragmento

 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { setHasOptionsMenu(true); if (view != null) { ViewGroup parent = (ViewGroup) view.getParent(); if (parent != null){ parent.removeView(view); } } try { view = inflater.inflate(R.layout.map_view, null); if(view!=null){ ViewGroup root = (ViewGroup) view.findViewById(R.id.root); ... @Override public void onDestroyView() { super.onDestroyView(); Fragment fragment = this.getSherlockActivity().getSupportFragmentManager().findFragmentById(R.id.map); if (fragment != null) getFragmentManager().beginTransaction().remove(fragment).commit(); } 

Tenía esto en viewPager y el desplome era porque cualquier fragmento tenía que tener su propia etiqueta, etiquetas duplicadas o los ids para el mismo fragmento no se permiten.

Creo que hubo algunos errores en la anterior App-Compat lib para el niño Fragment. He intentado @Vidar Wahlberg y ans @ Matt no funcionaron para mí. Después de actualizar la biblioteca appcompat mi código funciona perfectamente sin ningún esfuerzo adicional.

Cosas a tener en cuenta aquí es su aplicación se bloqueará mal en cualquiera de los dos casos: –

1) Para reutilizar fragmentos con Maps nuevamente MapView Fragment debe ser eliminado cuando tu fragmento mostrando Maps se reemplace con otro fragmento en la devolución de llamada onDestroyView.

De lo contrario cuando intenta inflar el mismo fragmento dos veces Duplicar ID, etiqueta nulo o identificador padre con otro fragmento para com.google.android.gms.maps.MapFragmento error ocurrirá.

2) En segundo lugar, no debe mezclar las operaciones de app.Fragment con las operaciones de la API android.support.v4.app.Fragment. Por ejemplo, no utilice android.app.FragmentTransaction para eliminar v4.app.Fragmento de tipo MapView Fragment. Mezclar esto resultará nuevamente en choque del lado del fragmento.

Aquí está un fragmento de código de ejemplo para el uso correcto de MapView

 import android.content.Context; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.support.v4.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.GoogleMap.OnMapClickListener; import com.google.android.gms.maps.MapFragment; import com.google.android.gms.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.CameraPosition; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.MarkerOptions; import com.serveroverload.yago.R; /** * @author 663918 * */ public class HomeFragment extends Fragment implements LocationListener { // Class to do operations on the Map GoogleMap googleMap; private LocationManager locationManager; public static Fragment newInstance() { return new HomeFragment(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.home_fragment, container, false); Bundle bdl = getArguments(); // setuping locatiomanager to perfrom location related operations locationManager = (LocationManager) getActivity().getSystemService( Context.LOCATION_SERVICE); // Requesting locationmanager for location updates locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 1, 1, this); // To get map from MapFragment from layout googleMap = ((MapFragment) getActivity().getFragmentManager() .findFragmentById(R.id.map)).getMap(); // To change the map type to Satellite // googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE); // To show our current location in the map with dot // googleMap.setMyLocationEnabled(true); // To listen action whenever we click on the map googleMap.setOnMapClickListener(new OnMapClickListener() { @Override public void onMapClick(LatLng latLng) { /* * LatLng:Class will give us selected position lattigude and * longitude values */ Toast.makeText(getActivity(), latLng.toString(), Toast.LENGTH_LONG).show(); } }); changeMapMode(2); // googleMap.setSatellite(true); googleMap.setTrafficEnabled(true); googleMap.setBuildingsEnabled(true); googleMap.setMyLocationEnabled(true); return v; } private void doZoom() { if (googleMap != null) { googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom( new LatLng(18.520430, 73.856744), 17)); } } private void changeMapMode(int mapMode) { if (googleMap != null) { switch (mapMode) { case 0: googleMap.setMapType(GoogleMap.MAP_TYPE_NONE); break; case 1: googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL); break; case 2: googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE); break; case 3: googleMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN); break; case 4: googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID); break; default: break; } } } private void createMarker(double latitude, double longitude) { // double latitude = 17.385044; // double longitude = 78.486671; // lets place some 10 random markers for (int i = 0; i < 10; i++) { // random latitude and logitude double[] randomLocation = createRandLocation(latitude, longitude); // Adding a marker MarkerOptions marker = new MarkerOptions().position( new LatLng(randomLocation[0], randomLocation[1])).title( "Hello Maps " + i); Log.e("Random", "> " + randomLocation[0] + ", " + randomLocation[1]); // changing marker color if (i == 0) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_AZURE)); if (i == 1) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_BLUE)); if (i == 2) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_CYAN)); if (i == 3) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_GREEN)); if (i == 4) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)); if (i == 5) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_ORANGE)); if (i == 6) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_RED)); if (i == 7) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_ROSE)); if (i == 8) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_VIOLET)); if (i == 9) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_YELLOW)); googleMap.addMarker(marker); // Move the camera to last position with a zoom level if (i == 9) { CameraPosition cameraPosition = new CameraPosition.Builder() .target(new LatLng(randomLocation[0], randomLocation[1])) .zoom(15).build(); googleMap.animateCamera(CameraUpdateFactory .newCameraPosition(cameraPosition)); } } } /* * creating random postion around a location for testing purpose only */ private double[] createRandLocation(double latitude, double longitude) { return new double[] { latitude + ((Math.random() - 0.5) / 500), longitude + ((Math.random() - 0.5) / 500), 150 + ((Math.random() - 0.5) * 10) }; } @Override public void onLocationChanged(Location location) { if (null != googleMap) { // To get lattitude value from location object double latti = location.getLatitude(); // To get longitude value from location object double longi = location.getLongitude(); // To hold lattitude and longitude values LatLng position = new LatLng(latti, longi); createMarker(latti, longi); // Creating object to pass our current location to the map MarkerOptions markerOptions = new MarkerOptions(); // To store current location in the markeroptions object markerOptions.position(position); // Zooming to our current location with zoom level 17.0f googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(position, 17f)); // adding markeroptions class object to the map to show our current // location in the map with help of default marker googleMap.addMarker(markerOptions); } } @Override public void onStatusChanged(String provider, int status, Bundle extras) { // TODO Auto-generated method stub } @Override public void onProviderEnabled(String provider) { // TODO Auto-generated method stub } @Override public void onProviderDisabled(String provider) { // TODO Auto-generated method stub } @Override public void onDestroyView() { // TODO Auto-generated method stub super.onDestroyView(); locationManager.removeUpdates(this); android.app.Fragment fragment = getActivity().getFragmentManager() .findFragmentById(R.id.map); if (null != fragment) { android.app.FragmentTransaction ft = getActivity() .getFragmentManager().beginTransaction(); ft.remove(fragment); ft.commit(); } } } 

XML

  <fragment android:id="@+id/map" android:name="com.google.android.gms.maps.MapFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> 

Resultado se parece a esto: – Introduzca aquí la descripción de la imagen

Espero que ayude a Alguien.

En esta solución no es necesario tomar variable estática;

 Button nextBtn; private SupportMapFragment mMapFragment; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); if (mRootView != null) { ViewGroup parent = (ViewGroup) mRootView.getParent(); Utility.log(0,"removeView","mRootView not NULL"); if (parent != null) { Utility.log(0, "removeView", "view removeViewed"); parent.removeAllViews(); } } else { try { mRootView = inflater.inflate(R.layout.dummy_fragment_layout_one, container, false);// } catch (InflateException e) { /* map is already there, just return view as it is */ e.printStackTrace(); } } return mRootView; } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); FragmentManager fm = getChildFragmentManager(); SupportMapFragment mapFragment = (SupportMapFragment) fm.findFragmentById(R.id.mapView); if (mapFragment == null) { mapFragment = new SupportMapFragment(); FragmentTransaction ft = fm.beginTransaction(); ft.add(R.id.mapView, mapFragment, "mapFragment"); ft.commit(); fm.executePendingTransactions(); } //mapFragment.getMapAsync(this); nextBtn = (Button) view.findViewById(R.id.nextBtn); nextBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Utility.replaceSupportFragment(getActivity(),R.id.dummyFragment,dummyFragment_2.class.getSimpleName(),null,new dummyFragment_2()); } }); }` 
 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <com.google.android.gms.maps.MapView android:id="@+id/mapview" android:layout_width="100dip" android:layout_height="100dip" android:layout_alignParentTop="true" android:layout_alignRight="@+id/textView1" android:layout_marginRight="15dp" > </com.google.android.gms.maps.MapView> 

¿Por qué no inserta un mapa utilizando el objeto MapView en lugar de MapFragment? No estoy seguro de si hay alguna limitación en MapView, aunque me pareció útil.

  • IllegalArgumentException al instanciar HttpClient en Android
  • Android - java.lang.IllegalArgumentException: contentIntent error requerido por la notificación?
  • Android - Error - IllegalArgumentException: El tipo de ventana no se puede cambiar después de agregar la ventana
  • Android TabView error?
  • Android Fragment no se encontró ninguna vista para ID?
  • OpenGL ES 2.0 IllegalArgumentException
  • Vista no adjunta al administrador de ventanas (cuál es la solución?)
  • Android IllegalArgumentException para dismissDialog
  • Java.lang.IllegalArgumentException: registra demasiados receptores de difusión
  • IllegalArgumentException: clase de estado incorrecta
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.