Error opening SupportMapFragment for second time

34,263

Solution 1

Instead of declaring de SupportMapFragment in layout, do it programatically and be sure you use getChildFragmentMananger instead of the classic getFragmentManager() to create the fragment.

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

Keep this SupportMapFragment mMapFragment as you will need it to retrieve the GoogleMap object:

  GoogleMap map = mMapFragment.getMap();

Solution 2

Update: As an alternative solution (which I think is much better) you can use a MapView which is described: here

I ran across a similar problem while working with a tabs implementation. With Google Maps V2, you are stuck with the SupportMapFragment, so using the MapView isn't an option. Between juanmeanwhile's post and comment #1 found here (https://code.google.com/p/gmaps-api-issues/issues/detail?id=5064#c1), I managed to figure out what I was doing wrong.

So, for anyone else getting the Duplicate id error, make sure you declare the fragment programatically, not in XML. This probably means nesting layouts.

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

Then you need to create your fragment programatically, but it needs to be done carefully with consideration for the Fragments lifecycle (http://developer.android.com/reference/android/app/Fragment.html#getChildFragmentManager()). To ensure everything is created at the right time, your code should look like this (taken from comment #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)));
    }
}
}

Hopefully this saves some time.

Solution 3

I've spend a half day resolving this trouble and only found a workaround. Override your onCreate method in YourFragment class:

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

And override your onDestroy method:

@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 :-(
    }
}

Solution 4

I had passed all this day looking for the solution to this problem, reading all the workaroung here, and I found this way to solve the problems. I will post all the code, because this question lacks a complete answer, just some tiny snippet that does match a full scenario and does help anybody.

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

}

By debugging this, you will notice that it does not matter how the fragment operates, you dont need botter for the onDestroyMethod, etc, since the validation of null, just operates with the current instance of the object.

Enjoy! ;)

Solution 5

I ran into this issue and found in my android logs that my hardware acceleration was not turned on. After I turned it on in my AndroidManifest I was displaying the maps multiple times was no longer an issue. I was using an x86 emulator.

Share:
34,263
Klaasvaak
Author by

Klaasvaak

Updated on July 13, 2022

Comments

  • Klaasvaak
    Klaasvaak almost 2 years

    When opening my SupportMapFragment (Android maps v2) for a second time (calling setContentView) I get the following 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
    

    The XML file:

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

    I have no idea what this error means. Can someone explain this?

    • CommonsWare
      CommonsWare about 11 years
      Do you have a View trying to inflate a layout containing a fragment? If so, why?
    • Klaasvaak
      Klaasvaak about 11 years
      I am. This is not the right way to use it? I am using SlidingMenu. In their docs they say setContentView needs to be called to show the main view. And the main view in this case is a view containing a fragment. link: github.com/jfeinstein10/SlidingMenu#simple-example
    • CommonsWare
      CommonsWare about 11 years
      I certainly would never do that.
    • Thomas Kaliakos
      Thomas Kaliakos about 11 years
      Did you eventually solve it?
    • Klaasvaak
      Klaasvaak about 11 years
      I used the MapView instead, I actually did not know there was a MapView as well.
    • Trino EGlez
      Trino EGlez over 10 years
      [This is a link that will help you, I was getting the same problem but this worked for me :)][1] [1]: stackoverflow.com/questions/14083950/…
    • jimbo82
      jimbo82 over 10 years
      I think this is the best solution: stackoverflow.com/a/19128882/1932352
  • Ben Sewards
    Ben Sewards almost 11 years
    Will this retain the maps instance across all fragments? Or will it be destroyed after onPause()?
  • Murphy
    Murphy over 10 years
    FYI you're not stuck with SupportMapFragment, MapView still exists and is fully functional: developers.google.com/maps/documentation/android/reference/c‌​om/…
  • Kaleb
    Kaleb over 10 years
    I think if you are using a Fragment you are in-fact stuck with MapFragment, and really SupportMapFragment if you want to support Honeycomb. If you are using an Activity, this is not the case and you can use a MapView (although I have no personally confirmed this). So, in my example, you are basically stuck with that implementation. If you were to use an Activity, you could use the MapView but you would still need to manage the life cycle.
  • alicanbatur
    alicanbatur over 10 years
    It does not solve the problem.It still crashes when i run it again.
  • alicanbatur
    alicanbatur over 10 years
    @Kaleb yes, but i fixed it. I tried lots of things, and finally i solve it. But, i really don't get how i fixed that.
  • jimpanzer
    jimpanzer over 10 years
    @Kaleb, thanks for idea. But really, I think google hate all of us.
  • Valerio Santinelli
    Valerio Santinelli over 10 years
    This answer lets you define your child fragments in XML layouts, which I find more manageable than having to replace pieces of layout with fragments programmatically.
  • jiahao
    jiahao over 10 years
    The code generates an error, which has been solved here: stackoverflow.com/questions/15207305/… (Markus answer)
  • Jaroslav
    Jaroslav over 10 years
    please pay attention to exception handling block, because you have risks to loose object's state!! This is why it's called workaround
  • Aiden Fry
    Aiden Fry almost 10 years
    Yes, you need to wait for a run before the map gets initialised. I use a delay handler to grab a reference to the map after 10 milliseconds, alternatively use the lifecycle to your advantage. i.e. commit the fragment in onCreate and then grab a reference to the map in onResume.
  • Analizer
    Analizer almost 10 years
    instead if the try-catch block I use if (f != null && f.isResumed()) {}, it works for me
  • TheDevMan
    TheDevMan over 9 years
    @Jaroslav: At what stage will I get an exception?
  • Marcelo
    Marcelo over 9 years
    After searching like a crazy over the web, this solution worked for me. Thanks!
  • gorbos
    gorbos over 9 years
    This also works for me and I think the best, based on the answers I saw myself that doesn't requires a MapView.
  • Jaroslav
    Jaroslav over 9 years
    @TheDevMan - for instance on display rotation } catch (IllegalStateException e) { //handle this situation because you are necessary will get //an exception here :-( }
  • Jaroslav
    Jaroslav over 9 years
    Please use this approach to solve the problem described above. And don't forget to delete setRetainInstance(true) in onCreate method code.google.com/p/gmaps-api-issues/issues/detail?id=5064#c1
  • ButterBeast
    ButterBeast about 9 years
    It worked for me! Thenk you, this should be the right answer.
  • Gabriel Kaffka
    Gabriel Kaffka about 9 years
    @juanmeanwhile , you should use getMapAsync() instead. MapFragment
  • Nicks
    Nicks over 8 years
    Hi, can you have a look on my problem, Its similar to what you explained, but not working for me. will be a great favor. Here is the link:-- stackoverflow.com/questions/32240138/…
  • Robert
    Robert over 8 years
    Thanks a bunch!! I have been stuck with this issue for over a week. Though I am using Xamarin Android (C#) but your solution worked perfectly!
  • voghDev
    voghDev over 7 years
    Have you managed to add "My location" button in the mapView? and also highlight the current user location in real time?
  • itzhar
    itzhar almost 7 years
    thanks a lot. I have view pager with 3 fragments, and this was exactly what i need