mapview - mapa en fragment android
Error al abrir SupportMapFragment por segunda vez (11)
Después de mucho Hit e intenta y finalmente logro usar MapView Fragment de manera perfecta en mi aplicación y el resultado es similar a este:
, aquí está mi clase de fragmento 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;
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(3);
// 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();
}
}
}
Mi archivo Xml se ve así: -
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Lo más importante a tener en cuenta es que la aplicación DO No Mix. El fragmento con la aplicación v4.Fragments else se bloqueará gravemente.
Como puede ver, he usado la aplicación. Fragmento para adjuntar y eliminar mi fragmento MapView
Espero que ayude a alguien
Al abrir mi SupportMapFragment (Android maps v2) por segunda vez (llamando a setContentView) aparece el siguiente error:
01-28 16:27:21.374: E/AndroidRuntime(32743): FATAL EXCEPTION: main
01-28 16:27:21.374: E/AndroidRuntime(32743): android.view.InflateException: Binary XML file line #6: Error inflating class fragment
01-28 16:27:21.374: E/AndroidRuntime(32743): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
01-28 16:27:21.374: E/AndroidRuntime(32743): at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
01-28 16:27:21.374: E/AndroidRuntime(32743): at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
01-28 16:27:21.374: E/AndroidRuntime(32743): at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
01-28 16:27:21.374: E/AndroidRuntime(32743): at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
01-28 16:27:21.374: E/AndroidRuntime(32743): at android.view.View.inflate(View.java:16119)
01-28 16:27:21.374: E/AndroidRuntime(32743): at mypackage.MyView.<init>(HitsView.java:26)
01-28 16:27:21.374: E/AndroidRuntime(32743): at mypackage.MenuListFragment.onItemClick(MenuListFragment.java:133)
01-28 16:27:21.374: E/AndroidRuntime(32743): at android.widget.AdapterView.performItemClick(AdapterView.java:298)
01-28 16:27:21.374: E/AndroidRuntime(32743): at android.widget.AbsListView.performItemClick(AbsListView.java:1086)
01-28 16:27:21.374: E/AndroidRuntime(32743): at android.widget.AbsListView$PerformClick.run(AbsListView.java:2855)
01-28 16:27:21.374: E/AndroidRuntime(32743): at android.widget.AbsListView$1.run(AbsListView.java:3529)
01-28 16:27:21.374: E/AndroidRuntime(32743): at android.os.Handler.handleCallback(Handler.java:615)
01-28 16:27:21.374: E/AndroidRuntime(32743): at android.os.Handler.dispatchMessage(Handler.java:92)
01-28 16:27:21.374: E/AndroidRuntime(32743): at android.os.Looper.loop(Looper.java:137)
01-28 16:27:21.374: E/AndroidRuntime(32743): at android.app.ActivityThread.main(ActivityThread.java:4745)
01-28 16:27:21.374: E/AndroidRuntime(32743): at java.lang.reflect.Method.invokeNative(Native Method)
01-28 16:27:21.374: E/AndroidRuntime(32743): at java.lang.reflect.Method.invoke(Method.java:511)
01-28 16:27:21.374: E/AndroidRuntime(32743): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
01-28 16:27:21.374: E/AndroidRuntime(32743): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
01-28 16:27:21.374: E/AndroidRuntime(32743): at dalvik.system.NativeStart.main(Native Method)
01-28 16:27:21.374: E/AndroidRuntime(32743): Caused by: java.lang.IllegalArgumentException: Binary XML file line #6: Duplicate id 0x7f04003b, tag null, or parent id 0x0 with another fragment for com.google.android.gms.maps.SupportMapFragment
01-28 16:27:21.374: E/AndroidRuntime(32743): at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:285)
01-28 16:27:21.374: E/AndroidRuntime(32743): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:676)
01-28 16:27:21.374: E/AndroidRuntime(32743): ... 20 more
El archivo XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="@+id/hits_map"
android:layout_width="match_parent"
android:layout_height="wrap_content"
class="com.google.android.gms.maps.SupportMapFragment"
map:mapType="normal"
map:uiZoomControls="false"
map:uiZoomGestures="true"
map:cameraZoom="13"
map:uiRotateGestures="true"
map:uiTiltGestures="true"/>
</RelativeLayout>
MyView.class:
public class MyView extends RelativeLayout {
private GoogleMap map;
public MyView(Context context, FragmentActivity activity) {
super(context);
inflate(activity, R.layout.activity_hits, this);
this.map = ((SupportMapFragment) activity.getSupportFragmentManager()
.findFragmentById(R.id.hits_map)).getMap();
}
}
No tengo idea de lo que significa este error. ¿Alguien puede explicar esto?
En lugar de declarar de SupportMapFragment en el diseño, hágalo programáticamente y asegúrese de usar getChildFragmentMananger en lugar del clásico getFragmentManager () para crear el fragmento.
mMapFragment = SupportMapFragment.newInstance();
FragmentTransaction fragmentTransaction =
mMapFragment.getChildFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.map_root, mMapFragment);
fragmentTransaction.commit();
Mantenga este SupportMapFragment mMapFragment ya que lo necesitará para recuperar el objeto GoogleMap:
GoogleMap map = mMapFragment.getMap();
Intenté varias soluciones propuestas aquí, y el mejor en mi humilde opinión es el MapView. De todos modos, encontré otra solución que podría satisfacer sus necesidades (o tal vez no).
Tenía mi SupportMapFragment
dentro de ViewPager+FragmentPagerAdapter
con 3 pestañas. Así que simplemente configuré el ViewPager de una manera que nunca destruye la pestaña donde está el SupportMapFragment
.
viewPager.setOffScreenPageLimit(2);
viewPager.setAdapter(...);
Con esta llamada, ViewPager siempre mantendrá dos páginas después y dos páginas antes de la actual, de modo que ninguna de mis tres pestañas nunca se destruirá / recreará.
Problema resuelto :)
Tenga en cuenta que el consumo de memoria aumentará
Me encontré con este problema y encontré en mis registros de Android que mi aceleración de hardware no estaba activada. Después de encenderlo en mi AndroidManifest, estaba visualizando los mapas varias veces y ya no era un problema. Estaba usando un emulador x86.
Me he pasado medio día resolviendo este problema y solo encontré una solución alternativa. Reemplace su método YourFragment
en YourFragment
clase YourFragment
:
public void onCreate(Bundle savedInstanceState) {
setRetainInstance(true);
super.onCreate(savedInstanceState);
}
Y anule su método onDestroy
:
@Override
public void onDestroyView() {
super.onDestroyView();
try {
SupportMapFragment fragment = (SupportMapFragment) getActivity()
.getSupportFragmentManager().findFragmentById(
R.id.multi_inns_on_map);
if (fragment != null) getFragmentManager().beginTransaction().remove(fragment).commit();
} catch (IllegalStateException e) {
//handle this situation because you are necessary will get
//an exception here :-(
}
}
Pasé todo este día buscando la solución a este problema, leyendo toda la solución aquí, y encontré esta manera de resolver los problemas. Publicaré todo el código, porque a esta pregunta le falta una respuesta completa, solo un pequeño fragmento que coincide con un escenario completo y ayuda a cualquiera.
public class LocationFragment extends Fragment implements View.OnClickListener {
private GoogleMap googleMap;
private static View rootView;
private SupportMapFragment supportMapFragment;
public LocationFragment() {
}
@Override
public void onDestroyView() {
super.onDestroyView();
}
@Override
public void onCreate(Bundle savedInstanceState) {
setRetainInstance(true);
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if(savedInstanceState == null) {
if (rootView != null) {
ViewGroup parent = (ViewGroup) rootView.getParent();
if (parent != null)
parent.removeView(rootView);
}
try{
if(rootView == null)
{
rootView = inflater.inflate(R.layout.fragment_location, container, false);
}
supportMapFragment = (SupportMapFragment) getFragmentManager().findFragmentById(R.id.map);
LocationUtility locationUtility = LocationUtility.getInstance(context);
GoogleMap googleMap = locationUtility.initilizeMap(supportMapFragment);
//More code
} catch (Exception e)
{
e.printStackTrace();
}
}
return rootView;
}
}
Al depurar esto, notará que no importa cómo funciona el fragmento, no necesita botter para onDestroyMethod, etc., ya que la validación de nulo solo funciona con la instancia actual del objeto.
¡Disfrutar! ;)
Tengo el mismo problema y lo solucioné al crear Google Map dinámicamente. Lo que tienes que hacer es crear una clase que extienda la clase SupportMapFragment .
Este método funciona en gingerbread a lollipop y en fragmentos anidados porque creará el mapa de forma dinámica, por lo que no tendrá que preocuparse por eliminar el fragmento ni nada de eso.
Paso 1:
public class DynamicMapFragment extends SupportMapFragment {
public GoogleMap googleMap;
public View mOriginalContentView;
public static int statusGooglePlayService;
@Override
public void onCreate(Bundle arg0) {
super.onCreate(arg0);
}
@Override
public View onCreateView(LayoutInflater mInflater, ViewGroup parent,
Bundle arg2) {
mOriginalContentView = super.onCreateView(mInflater, parent, arg2);
//this is for getting height of the phone screen
DisplayMetrics displaymetrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay()
.getMetrics(displaymetrics);
int height = displaymetrics.heightPixels;
//Here you can define the height of the map as you desire
FrameLayout.LayoutParams parentLayout = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, height / 3);
mOriginalContentView.setLayoutParams(parentLayout);
return mOriginalContentView;
}
@Override
public View getView() {
return mOriginalContentView;
}
@Override
public void onInflate(Activity arg0, AttributeSet arg1, Bundle arg2) {
super.onInflate(arg0, arg1, arg2);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
googleMap = getMap();
statusGooglePlayService = GooglePlayServicesUtil
.isGooglePlayServicesAvailable(getActivity());
if (statusGooglePlayService == ConnectionResult.SUCCESS) {
if (googleMap != null) {
// do whatever you want to do with map
}
} else {
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(
statusGooglePlayService, getActivity(), -1);
dialog.show();
}
}
}
Luego llama a la clase creada anteriormente desde Activity, Fragment como esta:
Paso 2:
//Calling the method from a fragment
private void createMap(View rootView) {
FrameLayout mapLayout = (FrameLayout)rootView.findViewById(R.id.location_map);
FragmentTransaction mTransaction = getActivity()
.getSupportFragmentManager().beginTransaction();
SupportMapFragment mFRaFragment = new DynamicMapFragment();
mTransaction.add(mapLayout.getId(), mFRaFragment);
mTransaction.commit();
try {
MapsInitializer.initialize(activity);
} catch (Exception e) {
e.printStackTrace();
}
}
Diseño XML para fragmento en el que tiene que agregar Framelayout en lugar de un fragmento para el mapa
Paso 3:
<?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" >
<FrameLayout
android:id="@+id/location_map"
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_weight="0" />
<!-- You can add any other view also whatever you want to add
<Button
android:layout_width="match_parent"
android:layout_height=""wrap_content""
android:layout_weight="0" /> -->
</LinearLayout>
prueba este código
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
finder = new LocationFinder(getActivity());
view = inflater.inflate(R.layout.fragment_secondfragement, container, false);
initMap();
// getLocation();
return view;
}
public void initMap(){
if (map == null) {
mapFragment = (SupportMapFragment) getChildFragmentManager()
.findFragmentById(R.id.map);
}
map = mapFragment.getMap();
map.setMyLocationEnabled(true);
map.getUiSettings().setMyLocationButtonEnabled(true);
}
solo ponte onCreateView
if (view != null) {
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null)
parent.removeView(view);
}
view = inflater.inflate(R.layout.map, container, false);
Actualización: como una solución alternativa (que creo que es mucho mejor) puede utilizar un MapView que se describe: here
Me encontré con un problema similar al trabajar con una implementación de pestañas. Con Google Maps V2, está atrapado con el SupportMapFragment, por lo que usar MapView no es una opción. Entre la publicación de juanmeanwhile y el comentario n. ° 1 que se encuentran aquí ( https://code.google.com/p/gmaps-api-issues/issues/detail?id=5064#c1 ), logré descubrir qué estaba haciendo mal.
Entonces, para cualquier otra persona que obtenga el error de Id. Duplicado, asegúrese de declarar el fragmento programáticamente, no en XML. Esto probablemente significa diseños de anidamiento.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Lots of fancy layout -->
<RelativeLayout
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</RelativeLayout>
</RelativeLayout>
Luego debe crear su fragmento programáticamente, pero debe hacerse cuidadosamente teniendo en cuenta el ciclo de vida de Fragments ( http://developer.android.com/reference/android/app/Fragment.html#getChildFragmentManager() ). Para asegurarse de que todo se crea en el momento correcto, su código debe verse así (tomado del comentario n. ° 1).
public class MyFragment extends Fragment {
private SupportMapFragment fragment;
private GoogleMap map;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.layout_with_map, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
FragmentManager fm = getChildFragmentManager();
fragment = (SupportMapFragment) fm.findFragmentById(R.id.map);
if (fragment == null) {
fragment = SupportMapFragment.newInstance();
fm.beginTransaction().replace(R.id.map, fragment).commit();
}
}
@Override
public void onResume() {
super.onResume();
if (map == null) {
map = fragment.getMap();
map.addMarker(new MarkerOptions().position(new LatLng(0, 0)));
}
}
}
Espero que esto ahorre algo de tiempo.
private MainActivity mainActObj;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mainActObj = getMainActivity();
}
@SuppressWarnings("unchecked")
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (mainActObj.mapView == null) {
return mainActObj.mapView = inflater.inflate(R.layout.fragment_map,
null);
}
else {
ViewGroup parent = (ViewGroup) mainActObj.mapView.getParent();
if (parent != null) {
parent.removeView(mainActObj.mapView);
}
try {
return mainActObj.mapView = inflater.inflate(
R.layout.fragment_map, container, false);
} catch (InflateException except) {
return mainActObj.mapView;
}
}
}