How to put Google Maps V2 on a Fragment using ViewPager

AndroidGoogle MapsAndroid Fragments

Android Problem Overview


I am trying to do a tab layout same in Play Store. I got to display the tab layout using a fragments and viewpager from androidhive. However, I can't implement google maps v2 on it. I searched the internet for hours already, but I can't find a tutorial on how to do it. Can some one please show me how?

Android Solutions


Solution 1 - Android

By using this code we can setup MapView anywhere, inside any ViewPager or Fragment or Activity.

In the latest update of Google for Maps, only MapView is supported for fragments. MapFragment & SupportMapFragment didn't work for me.

Setting up the layout for showing the map in the file location_fragment.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.google.android.gms.maps.MapView
        android:id="@+id/mapView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

Now, we setup the Java class for showing the map in the file MapViewFragment.java:

public class MapViewFragment extends Fragment {

    MapView mMapView;
    private GoogleMap googleMap;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
	    View rootView = inflater.inflate(R.layout.location_fragment, container, false);

        mMapView = (MapView) rootView.findViewById(R.id.mapView);
        mMapView.onCreate(savedInstanceState);

        mMapView.onResume(); // needed to get the map to display immediately

        try {
            MapsInitializer.initialize(getActivity().getApplicationContext());
        } catch (Exception e) {
            e.printStackTrace();
        }

        mMapView.getMapAsync(new OnMapReadyCallback() {
            @Override
            public void onMapReady(GoogleMap mMap) {
                googleMap = mMap;

                // For showing a move to my location button
	            googleMap.setMyLocationEnabled(true);

                // For dropping a marker at a point on the Map
                LatLng sydney = new LatLng(-34, 151);
                googleMap.addMarker(new MarkerOptions().position(sydney).title("Marker Title").snippet("Marker Description"));
            
                // For zooming automatically to the location of the marker
                CameraPosition cameraPosition = new CameraPosition.Builder().target(sydney).zoom(12).build();
                googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
            }
        });

        return rootView;
    }

    @Override
    public void onResume() {
        super.onResume();
        mMapView.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();
        mMapView.onPause();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mMapView.onDestroy();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        mMapView.onLowMemory();
    }
}

Finally you need to get the API Key for your app by registering your app at Google Cloud Console. Register your app as Native Android App.

Solution 2 - Android

The following approach works for me.

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

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.MapsInitializer;
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;

/**
 * A fragment that launches other parts of the demo application.
 */
public class MapFragment extends Fragment {

MapView mMapView;
private GoogleMap googleMap;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
		Bundle savedInstanceState) {
	// inflat and return the layout
	View v = inflater.inflate(R.layout.fragment_location_info, container,
			false);
	mMapView = (MapView) v.findViewById(R.id.mapView);
	mMapView.onCreate(savedInstanceState);

	mMapView.onResume();// needed to get the map to display immediately

	try {
		MapsInitializer.initialize(getActivity().getApplicationContext());
	} catch (Exception e) {
		e.printStackTrace();
	}

	googleMap = mMapView.getMap();
	// latitude and longitude
	double latitude = 17.385044;
	double longitude = 78.486671;

	// create marker
	MarkerOptions marker = new MarkerOptions().position(
			new LatLng(latitude, longitude)).title("Hello Maps");

	// Changing marker icon
	marker.icon(BitmapDescriptorFactory
			.defaultMarker(BitmapDescriptorFactory.HUE_ROSE));

	// adding marker
	googleMap.addMarker(marker);
	CameraPosition cameraPosition = new CameraPosition.Builder()
			.target(new LatLng(17.385044, 78.486671)).zoom(12).build();
	googleMap.animateCamera(CameraUpdateFactory
			.newCameraPosition(cameraPosition));

	// Perform any camera updates here
	return v;
}

@Override
public void onResume() {
	super.onResume();
	mMapView.onResume();
}

@Override
public void onPause() {
	super.onPause();
	mMapView.onPause();
}

@Override
public void onDestroy() {
	super.onDestroy();
	mMapView.onDestroy();
}

@Override
public void onLowMemory() {
	super.onLowMemory();
	mMapView.onLowMemory();
}
}

fragment_location_info.xml

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.gms.maps.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent" />

Solution 3 - Android

You can use this line if you want to use GoogleMap in a fragment:

<fragment
            android:id="@+id/map"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            class="com.google.android.gms.maps.SupportMapFragment" />

GoogleMap mGoogleMap = ((SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map)).getMap();

Solution 4 - Android

Latest stuff with getMapAsync instead of the deprecated one.

1. check manifest for

<meta-data android:name="com.google.android.geo.API_KEY" android:value="xxxxxxxxxxxxxxxxxxxxxxxxx"/>

You can get the API Key for your app by registering your app at Google Cloud Console. Register your app as Native Android App

2. in your fragment layout .xml add FrameLayout(not fragment):

                  <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="250dp"
                android:layout_weight="2"
                android:name="com.google.android.gms.maps.SupportMapFragment"
                android:id="@+id/mapwhere" />

or whatever height you want

3. In onCreateView in your fragment

    private SupportMapFragment mSupportMapFragment; 

    mSupportMapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.mapwhere);
    if (mSupportMapFragment == null) {
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        mSupportMapFragment = SupportMapFragment.newInstance();
        fragmentTransaction.replace(R.id.mapwhere, mSupportMapFragment).commit();
    }

    if (mSupportMapFragment != null)
    {
        mSupportMapFragment.getMapAsync(new OnMapReadyCallback() {
            @Override public void onMapReady(GoogleMap googleMap) {
                if (googleMap != null) {

                    googleMap.getUiSettings().setAllGesturesEnabled(true);

                      -> marker_latlng // MAKE THIS WHATEVER YOU WANT

                        CameraPosition cameraPosition = new CameraPosition.Builder().target(marker_latlng).zoom(15.0f).build();
                        CameraUpdate cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition);
                        googleMap.moveCamera(cameraUpdate);

                }

            }
        });

Solution 5 - Android

here what i did in detail:

From here you can get google map api key

alternative and simple way

first log in to your google account and visit google libraries and select Google Maps Android API

dependency found in android studio default map activity :

compile 'com.google.android.gms:play-services:10.0.1'

put your key into android mainifest file under application like below

in AndroidMainifest.xml make these changes:

    // required permission
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />


        // google map api key put under/inside <application></application>
        // android:value="YOUR API KEY"
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="AIzasdfasdf645asd4f847sad5f45asdf7845" />



        

Fragment code :

public class MainBranchFragment extends Fragment implements OnMapReadyCallback{

private GoogleMap mMap;
    public MainBranchFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view= inflater.inflate(R.layout.fragment_main_branch, container, false);
        SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.main_branch_map);
        mapFragment.getMapAsync(this);
        return view;
    }


   

     @Override
        public void onMapReady(GoogleMap googleMap) {
            mMap = googleMap;
            LatLng UCA = new LatLng(-34, 151);
            mMap.addMarker(new MarkerOptions().position(UCA).title("YOUR TITLE")).showInfoWindow();
          
            mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(UCA,17));
    
        }
    }

in you fragment xml :

<fragment
                android:id="@+id/main_branch_map"
                android:name="com.google.android.gms.maps.SupportMapFragment"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context="com.googlemap.googlemap.MapsActivity" />

Solution 6 - Android

For the issue of getting a NullPointerException when we change the Tabs in a FragmentTabHost you just need to add this code to your class which has the TabHost. I mean the class where you initialize the tabs. This is the code :

/**** Fix for error : Activity has been destroyed, when using Nested tabs 
 * We are actually detaching this tab fragment from the `ChildFragmentManager`
 * so that when this inner tab is viewed back then the fragment is attached again****/

import java.lang.reflect.Field;

@Override
public void onDetach() {
	super.onDetach();
	try {
		Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
		childFragmentManager.setAccessible(true);
		childFragmentManager.set(this, null);
	} catch (NoSuchFieldException e) {
		throw new RuntimeException(e);
	} catch (IllegalAccessException e) {
		throw new RuntimeException(e);
	}
}

Solution 7 - Android

public class DemoFragment extends Fragment {

  
MapView mapView;
GoogleMap map;
LatLng CENTER = null;

public LocationManager locationManager;

double longitudeDouble;
double latitudeDouble;

String snippet;
String title;
Location location;
String myAddress;

String LocationId;
String CityName;
String imageURL;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
		Bundle savedInstanceState) {
	// TODO Auto-generated method stub
	View view = inflater
				.inflate(R.layout.fragment_layout, container, false);

    mapView = (MapView) view.findViewById(R.id.mapView);
		mapView.onCreate(savedInstanceState);

  setMapView();


 }

 private void setMapView() {
	try {
		MapsInitializer.initialize(getActivity());

		switch (GooglePlayServicesUtil
				.isGooglePlayServicesAvailable(getActivity())) {
		case ConnectionResult.SUCCESS:
			// Toast.makeText(getActivity(), "SUCCESS", Toast.LENGTH_SHORT)
			// .show();

			// Gets to GoogleMap from the MapView and does initialization
			// stuff
			if (mapView != null) {

				locationManager = ((LocationManager) getActivity()
						.getSystemService(Context.LOCATION_SERVICE));

				Boolean localBoolean = Boolean.valueOf(locationManager
						.isProviderEnabled("network"));

				if (localBoolean.booleanValue()) {

					CENTER = new LatLng(latitude, longitude);

				} else {
					
				}
				map = mapView.getMap();
				if (map == null) {

					Log.d("", "Map Fragment Not Found or no Map in it!!");

				}

				map.clear();
				try {
					map.addMarker(new MarkerOptions().position(CENTER)
							.title(CityName).snippet(""));
				} catch (Exception e) {
					e.printStackTrace();
				}

				map.setIndoorEnabled(true);
				map.setMyLocationEnabled(true);
				map.moveCamera(CameraUpdateFactory.zoomTo(5));
				if (CENTER != null) {
					map.animateCamera(
							CameraUpdateFactory.newLatLng(CENTER), 1750,
							null);
				}
				// add circle
				CircleOptions circle = new CircleOptions();
				circle.center(CENTER).fillColor(Color.BLUE).radius(10);
				map.addCircle(circle);
				map.setMapType(GoogleMap.MAP_TYPE_NORMAL);

			}
			break;
		case ConnectionResult.SERVICE_MISSING:

			break;
		case ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED:

			break;
		default:

		}
	} catch (Exception e) {

	}

}

in fragment_layout

<com.google.android.gms.maps.MapView
                android:id="@+id/mapView"
                android:layout_width="match_parent"
                android:layout_height="160dp"                    
                android:layout_marginRight="10dp" />

Solution 8 - Android

When you add yor map use:

getChildFragmentManager().beginTransaction()
    .replace(R.id.menu_map_container, mapFragment, "f" + shabbatIndex).commit();

instead of .add and instead of getFragmentManager.

Solution 9 - Android

This is the Kotlin way:

In fragment_map.xml you should have:

<?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.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

In your MapFragment.kt you should have:

    private fun setupMap() {
        (childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?)!!.getMapAsync(this)
    }

Call setupMap() in onCreateView.

Solution 10 - Android

According to https://developer.android.com/about/versions/android-4.2.html#NestedFragments, you can use nested fragments to achieve this by calling getChildFragmentManager() if you still want to use the Google Maps fragment instead of the view inside your own fragment:

SupportMapFragment mapFragment = new SupportMapFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.content, mapFragment).commit();

where "content" is the root layout in your fragment (preferably a FrameLayout). The advantage of using a map fragment is that then the map lifecycle is managed automatically by the system.

Although the documentation says "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. ", I have somehow successfully done this and it worked fine. Here is my code:
In the fragment's onCreateView() method:

View view = inflater.inflate(R.layout.layout_maps, container, false);
SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(...);

In the layout:

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/map"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Hope it helps!

Solution 11 - Android

i just create MapActivity and inflate it to fragment . MapActivity.java:

package com.example.ahmedsamra.mansouratourguideapp;

import android.support.v4.app.FragmentActivity;
import android.os.Bundle;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {

    private GoogleMap mMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_categories);//layout for container
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, new MapFragment())
                .commit();
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }


    /**
     * Manipulates the map once available.
     * This callback is triggered when the map is ready to be used.
     * This is where we can add markers or lines, add listeners or move the camera. In this case,
     * we just add a marker near Sydney, Australia.
     * If Google Play services is not installed on the device, the user will be prompted to install
     * it inside the SupportMapFragment. This method will only be triggered once the user has
     * installed Google Play services and returned to the app.
     */
    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;

        // Add a marker in Sydney and move the camera
        LatLng mansoura = new LatLng(31.037933, 31.381523);
        mMap.addMarker(new MarkerOptions().position(mansoura).title("Marker in mansoura"));
        mMap.moveCamera(CameraUpdateFactory.newLatLng(mansoura));
    }
}

activity_map.xml:

<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:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.ahmedsamra.mansouratourguideapp.MapsActivity" />

MapFragment.java:-

package com.example.ahmedsamra.mansouratourguideapp;


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

/**
 * A simple {@link Fragment} subclass.
 */
public class MapFragment extends Fragment {


    public MapFragment() {
        // Required empty public constructor
    }


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

}

Solution 12 - Android

I've a workaround for NullPointerException when remove fragment in on DestoryView, Just put your code in onStop() not onDestoryView. It works fine!

@Override
public void onStop() {
    super.onStop();
    if (mMap != null) {
        MainActivity.fragmentManager.beginTransaction()
                .remove(MainActivity.fragmentManager.findFragmentById(R.id.location_map)).commit();
        mMap = null;
    }
}

Solution 13 - Android

Dynamically adding map fragment to view Pager:

If you are targeting an application earlier than API level 12 make an instance of SupportedMapFragment and add it to your view page adapter.

SupportMapFragment supportMapFragment=SupportMapFragment.newInstance();
        supportMapFragment.getMapAsync(this);

API level 12 or higher support MapFragment objects

MapFragment mMapFragment=MapFragment.newInstance();
            mMapFragment.getMapAsync(this);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJeongbebsView Question on Stackoverflow
Solution 1 - AndroidarshuView Answer on Stackoverflow
Solution 2 - AndroidBrandon YangView Answer on Stackoverflow
Solution 3 - AndroidMaddyView Answer on Stackoverflow
Solution 4 - AndroidOWADVLView Answer on Stackoverflow
Solution 5 - AndroiddharmxView Answer on Stackoverflow
Solution 6 - AndroidarshuView Answer on Stackoverflow
Solution 7 - AndroidVaishali SutariyaView Answer on Stackoverflow
Solution 8 - Androiduser1396018View Answer on Stackoverflow
Solution 9 - AndroidGilbertView Answer on Stackoverflow
Solution 10 - AndroidShreck YeView Answer on Stackoverflow
Solution 11 - Androidahmed samraView Answer on Stackoverflow
Solution 12 - AndroidIbrahim AbdelGawadView Answer on Stackoverflow
Solution 13 - AndroidAdeeb karimView Answer on Stackoverflow