第二次打开SupportMapFragment时出错

当第二次打开我的SupportMapFragment(Android maps v2)(调用setContentView)时,出现以下错误:

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 

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

我不知道这个错误是什么意思。 有人可以解释这个吗?

不是在布局中声明de SupportMapFragment,而是以编程方式执行,并确保使用getChildFragmentMananger而不是传统的getFragmentManager()来创build片段。

  mMapFragment = SupportMapFragment.newInstance(); FragmentTransaction fragmentTransaction = mMapFragment.getChildFragmentManager().beginTransaction(); fragmentTransaction.add(R.id.map_root, mMapFragment); fragmentTransaction.commit(); 

请保留此SupportMapFragment mMapFragment,因为您将需要它来检索GoogleMap对象:

  GoogleMap map = mMapFragment.getMap(); 

更新:作为一个替代解决scheme(我认为更好),你可以使用一个MapView: 这里描述

在处理标签实现时,我遇到了类似的问题。 使用Google Maps V2时,您只能使用SupportMapFragment,因此不能使用MapView。 在这里发表评论#1和发现在这里( https://code.google.com/p/gmaps-api-issues/issues/detail?id=5064#c1 ),我设法弄清楚我做错了什么。

所以,对于任何其他人得到重复的id错误,请确保您以编程方式声明片段,而不是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" > <!-- Lots of fancy layout --> <RelativeLayout android:id="@+id/map" android:layout_width="match_parent" android:layout_height="wrap_content"> </RelativeLayout> </RelativeLayout> 

然后你需要以编程方式创build你的片段,但是需要仔细考虑片段生命周期( http://developer.android.com/reference/android/app/Fragment.html#getChildFragmentManager(); )。 为了确保在正确的时间创build一切,你的代码应该像这样(来自注释#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))); } } } 

希望这可以节省一些时间。

我已经花了半天的时间解决了这个问题,只find了解决办法。 覆盖YourFragment类中的onCreate方法:

 public void onCreate(Bundle savedInstanceState) { setRetainInstance(true); super.onCreate(savedInstanceState); } 

并重写你的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 :-( } } 

这一天我一直在寻找解决这个问题的办法,在这里阅读所有的工作,我find了解决这个问题的办法。 我将发布所有的代码,因为这个问题没有一个完整的答案,只是一些小的片段,完全匹配一个完整的场景,并帮助任何人。

 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; } } 

通过debugging,你会注意到片段的运行方式并不重要,你不需要为onDestroyMethod创buildbotter等,因为null的validation只是在对象的当前实例下运行。

请享用! ;)

我遇到了这个问题,并在我的Android日志中发现我的硬件加速未打开。 在AndroidManifest中打开之后,我多次显示地图不再是问题。 我正在使用x86模拟器。

经过大量的命中和尝试,我终于成功地在我的应用程序中使用MapView Fragment,结果如下所示:

在这里输入图像说明

,这里是我的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(); } } } 

我的Xml文件看起来像这样:

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

最重要的是要注意的是,不要混用app.Fragment与v4.Fragments其他应用程序将严重崩溃。

正如你所看到的,我已经使用app.Fragment来附加和删除我的MapView片段

希望它会帮助别人

我尝试了这里提出的各种解决scheme,最好的一个恕我直言是MapView。 无论如何,我发现另一个解决scheme,可以满足您的需求(或者不)。

我有一个ViewPager+FragmentPagerAdapter有3个选项卡的我的SupportMapFragment 。 所以我刚刚configurationViewPager的方式,它永远不会破坏SupportMapFragment的标签。

 viewPager.setOffScreenPageLimit(2); viewPager.setAdapter(...); 

通过这个调用,ViewPager将始终在当前页面之前和之后两页保留两个页面,所以我的三个选项卡都不会被销毁/重新创build。

问题解决了 :)

请注意,内存消耗会增加

 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; } } } 

试试这个代码

  @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); } 

我有同样的问题,通过dynamic创build谷歌地图解决。 你所要做的就是创build一个正在扩展SupportMapFragment类的类。

这种方法适用于姜饼,棒棒糖嵌套片段,因为它会dynamic地创build地图,所以不必担心删除片段或类似的东西。

步骤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(); } } } 

然后从Activity,Fragment调用上面创build的类,如下所示:

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

XML布局的片段,你必须添加Framelayout而不是map的片段

第三步:

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

只要把onCreateView

 if (view != null) { ViewGroup parent = (ViewGroup) view.getParent(); if (parent != null) parent.removeView(view); } view = inflater.inflate(R.layout.map, container, false);