Android - SupportMapFragment with GoogleMaps API 2.0 giving IllegalArgumentException
Asked Answered
B

11

14

I am trying to use the latest Map API 2.0 provided for Android. I am using the Support Library as I want to support Android 2.2. Following is my code:

Main Activity class

public class MainActivity extends FragmentActivity {

    public FragmentManager fManager ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        fManager = getSupportFragmentManager();
        Button showMapButton = (Button) findViewById(R.id.showMapButton);
        showMapButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                loadMapFragment();
            }
        });
    }

    private void loadMapFragment() {
        MapPageFragment plotterFragment = new MapPageFragment();
        FragmentTransaction ft = fManager.beginTransaction();
        ft.replace(R.id.allFragmentsFrameLayout, plotterFragment);
        ft.addToBackStack(null);
        ft.commit();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}

Main Activity layout file

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/showMapButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Show Map"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="30dp"
        android:layout_marginTop="30dp"
        android:layout_alignParentTop="true" />


    <FrameLayout
        android:id="@+id/allFragmentsFrameLayout"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_alignParentTop="true">
        <!-- Put fragments dynamically -->
    </FrameLayout>

</RelativeLayout>

Map Fragment Class

public class MapPageFragment extends SupportMapFragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
                                         Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        return inflater.inflate(R.layout.map_fragment_layout, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    }
}

Map Fragment Layout

<?xml version="1.0" encoding="utf-8"?>
<fragment
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:map="http://schemas.android.com/apk/res-auto"
    android:id="@+id/map"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    class="com.google.android.gms.maps.SupportMapFragment"
    map:uiCompass="true"
    map:mapType= "normal"
    map:uiRotateGestures="true"
    map:uiScrollGestures="true"
    map:uiTiltGestures="true"
    map:uiZoomControls="true"
    map:uiZoomGestures="true" />

Android Manifest File

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mapfragmentexample"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />

    <permission
        android:name="com.plotter.permission.MAPS_RECEIVE"
        android:protectionLevel="signature"/>
    <uses-permission android:name="com.plotter.permission.MAPS_RECEIVE"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>

    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="AIzaSyA5FtIeLQ1gGUihZIZPQVi3Yz_0l4NG9PY"/>
    </application>

</manifest>

Everything is working fine for the first time. i.e. When I click on the Show Map button the map fragment gets loaded and displays the map. When I press back button, the map fragment is unloaded and I can see the Show Map button again.

I face an issue when I press the Show Map button again. I get the following error:

FATAL EXCEPTION: main
android.view.InflateException: Binary XML file line #2: Error inflating class fragment
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:699)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:468)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
    at com.mapfragmentexample.MapPageFragment.onCreateView(MapPageFragment.java:17)
    at android.support.v4.app.Fragment.performCreateView(Fragment.java:1460)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:911)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
    at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1444)
    at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:429)
    at android.os.Handler.handleCallback(Handler.java:605)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4503)
    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:809)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:576)
    at dalvik.system.NativeStart.main(Native Method)

Caused by: java.lang.IllegalArgumentException: Binary XML file line #2: 
       Duplicate id 0x7f040006, tag null, or parent id 0x0 with another fragment 
       for com.google.android.gms.maps.SupportMapFragment
    at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:285)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:671)
    ... 18 more

I am not getting where I am getting wrong or missing anything.

Bombsight answered 2/1, 2013 at 15:13 Comment(5)
have you solved your problem? I'm facing the same thingMccracken
@Mccracken I have the same problem...let me know if you fix itSaharan
@Mccracken I don't think you should use that :)Saharan
@Saharan If you know better way I will fully appreciate itMccracken
Have you find better solution for that? I am also facing the same problem.Morphophoneme
M
49

You can fix this, if you delete all nested fragments in onDestroyView(). Don't know if it is a proper solution.

public void onDestroyView() {
   super.onDestroyView(); 
   Fragment fragment = (getFragmentManager().findFragmentById(R.id.map));   
   FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
   ft.remove(fragment);
   ft.commit();
}

And inflating them as usual in onCreateView()

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    return inflater.inflate(R.layout.map, container, false);
}
Mccracken answered 8/2, 2013 at 8:16 Comment(4)
This does not work during screen orientationDismissive
add ft.commitAllowingStateLoss(); If u want to handle orientation as well.Dismissive
This is a hack and not a proper solution. It would certainly crash in certain circumstances, like orientation change or using fragments in view pager.Categorical
Better use ft.commitAllowingStateLoss(); instead because you cannot commit changes after onSaveInstanceStateShemikashemite
T
9

You need to use getChildFragmentManager() to add SupportMapFragment not not through xml.

For "why", see official documentation: http://developer.android.com/about/versions/android-4.2.html#NestedFragments

Take a look at my answer here: https://mcmap.net/q/495598/-mapfragment-in-fragment-alternatives

Tsar answered 21/3, 2013 at 8:6 Comment(1)
I'm currently using Natalia's solution and I'd like to have a try on your suggestion. ThanksPhelips
M
2

You cannot inflate a layout into a fragment when that layout includes a fragment. Nested fragments are only supported when added to a fragment dynamically. More detail here!

Malleable answered 6/11, 2013 at 22:51 Comment(0)
C
2

Used this solution (similar to others):

public void onDestroyView() {

    FragmentManager fm = getActivity().getSupportFragmentManager();
    Fragment fragment = (fm.findFragmentById(R.id.map));

    if (fragment.isResumed()) {
        FragmentTransaction ft = fm.beginTransaction();
        ft.remove(fragment);
        ft.commit();
    }
    super.onDestroyView();
}

I had problems before using the if (fragment.isResumed).

Chamness answered 27/5, 2014 at 9:52 Comment(0)
S
0

I was facing the same issue in JakeWhartonViewPagerIndicatore along with SherlockFragments. Here is sample TestFragment with solved issue, thanks to Natalia for providing above solution. Your fragment may be a little different from mine.

Reference: Making ActionBarSherlock and ViewPagerIndicator play nice

Good Luck..!!

package com.example.vpiabstest;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.actionbarsherlock.app.SherlockFragment;

public class TestFragment extends SherlockFragment {
    private String mContent = "???";
    private String text;
    private static final String KEY_TAB_NUM = "key.tab.num";

    public static TestFragment newInstance(String text) {
        TestFragment fragment = new TestFragment();

        // Supply num input as an argument.
        Bundle args = new Bundle();
        args.putString(KEY_TAB_NUM, text);
        fragment.setArguments(args);


        return fragment;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        text = getString(R.string.tab_page_num) + mContent;

        View view = null;

        if(text.contains("2")) {
            view = inflater.inflate(R.layout.pinpoints_list, null);
        } else if(text.contains("1")) {
            view = inflater.inflate(R.layout.main_fragment_activity, null);
        } else {
            view = inflater.inflate(R.layout.activity_main, null);
            ((TextView)view.findViewById(R.id.text)).setText(text);
        }


        return view;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContent =  getArguments() != null ? getArguments().getString(KEY_TAB_NUM) : "???";
    }

    public void onDestroyView() {
        super.onDestroyView();

        // Your Programing skills goes here

        if(text == null || !text.contains("1")) {
            return;
        }

        // Do Not Miss this
        try {
            Fragment fragment = (getFragmentManager().findFragmentById(R.id.map_fragment));  
            FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
            ft.remove(fragment);
            ft.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Scampi answered 19/2, 2013 at 9:33 Comment(0)
E
0

Use dialog.SetContentView() method in your activity's onCreate() cause when we tring to load.

Dialog again it loads only dialog not the whole activity life cycle and leads it to exception of Duplicate id.

Try it.

Easeful answered 13/10, 2014 at 7:52 Comment(0)
A
0

Try this

Maps fragment layout

<?xml version="1.0" encoding="utf-8"?>
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
map:uiCompass="true"
map:mapType= "normal"
map:uiRotateGestures="true"
map:uiScrollGestures="true"
map:uiTiltGestures="true"
map:uiZoomControls="true"
map:uiZoomGestures="true" 
tools:context="the.package.name.of.mappagefragment.MapPageFragment" />

Map fragment class

public class MapPageFragment extends SupportMapFragment 
{

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
{
    View rootView = super.onCreateView(inflater, container, savedInstanceState);
    if (rootView == null)
    {
        rootView = inflater.inflate(R.layout.map_fragment_layout, container, false);
    }
    return rootView;
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) 
{
    super.onViewCreated(view, savedInstanceState);
}
}
Audy answered 15/2, 2015 at 8:13 Comment(0)
M
0

I used Natalia response but at times broke the application. Use this one and it worked perfectly without breaking.

@Override
public void onDestroyView() {

  try{
    FragmentTransaction transaction = getSupportFragmentManager()
            .beginTransaction();

    transaction.remove(nestedFragment);

    transaction.commit();
  }catch(Exception e){
  }

    super.onDestroyView();
}

https://mcmap.net/q/95372/-fragments-within-fragments

Manis answered 25/10, 2015 at 22:29 Comment(0)
D
0
Fragment fragment = (getChildFragmentManager().findFragmentById(R.id.mapview));
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.remove(fragment);
ft.commit();

Use this saves the day.

Dactylography answered 28/6, 2016 at 4:18 Comment(0)
D
0

Use intent flags:

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

when calling main activity.

Dactylography answered 24/8, 2016 at 18:8 Comment(0)
C
-2

I had the same problem. Try adding ...

android:name="com.mapfragmentexample.MapPageFragment"

... to fragment in the layout file!

Couperin answered 21/2, 2013 at 15:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.