Nik
Nik

Reputation: 3133

Android - SupportMapFragment with GoogleMaps API 2.0 giving IllegalArgumentException

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.

Upvotes: 14

Views: 43785

Answers (11)

Praseed M
Praseed M

Reputation: 161

Use intent flags:

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

when calling main activity.

Upvotes: 0

Praseed M
Praseed M

Reputation: 161

Fragment fragment = (getChildFragmentManager().findFragmentById(R.id.mapview));
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.remove(fragment);
ft.commit();

Use this saves the day.

Upvotes: 0

Emmanuelguther
Emmanuelguther

Reputation: 1059

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://stackoverflow.com/a/7953801/3364157

Upvotes: 0

user4568328
user4568328

Reputation: 1

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

Upvotes: 0

suraj bokankar
suraj bokankar

Reputation: 1

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.

Upvotes: 0

sourcerebels
sourcerebels

Reputation: 5180

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).

Upvotes: 2

ToolFan
ToolFan

Reputation: 650

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!

Upvotes: 2

Natalia
Natalia

Reputation: 783

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

Upvotes: 49

user1851212
user1851212

Reputation: 701

I had the same problem. Try adding ...

android:name="com.mapfragmentexample.MapPageFragment"

... to fragment in the layout file!

Upvotes: -2

MaciejG&#243;rski
MaciejG&#243;rski

Reputation: 22232

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://stackoverflow.com/a/15512285/2183804

Upvotes: 9

Rizwan Sohaib
Rizwan Sohaib

Reputation: 1260

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

Upvotes: 0

Related Questions