Null pointer exception in fragment, using google maps - android

I received a null pointer exception when getting android google maps in a fragment. The error is at the line findFragmentById.I tried using
if (mMap != null) and it indicates that the map is still null. What can I do to resolve this?
In MapActivity.java,
//Relevant imports
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
enter code here
public class MapView extends Fragment {
GoogleMap mMap;
LatLng mLocation = new LatLng(1.379348, 103.849876);
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.map_view, container, false);
mMap = ((SupportMapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
//Zoom
mMap.getUiSettings().setZoomControlsEnabled(true);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(mLocation, 17));
Marker mMarker = mMap.addMarker(new MarkerOptions()
.position(mLocation)
.title("School")
.snippet("NTU")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_launcher)));
mMap.setOnMarkerClickListener(new OnMarkerClickListener()
{
public boolean onMarkerClick(Marker marker){
Toast.makeText(getActivity().getApplicationContext(), "Welcome to " + marker.getTitle(), Toast.LENGTH_LONG);
return false;
}
});
mMap.setOnInfoWindowClickListener(new OnInfoWindowClickListener(){
#Override
public void onInfoWindowClick(Marker arg0) {
// TODO Auto-generated method stub
}
});
return rootView;
}
}
In map_view.xml,
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</RelativeLayout>

In order to have a SupportMapFragment nested inside a Fragment, you need to use getChildFragmentManager() instead of getFragmentManager().
So, you would change this:
mMap = ((SupportMapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
To this, and also move all of the code referencing mMap to onResume():
mMap = ((SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map)).getMap();
If you go this route you will also need to fix your layout xml to use a SupportMapFragment:
<fragment
android:id="#+id/map"
class="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
However, it would be best to not have nested Fragments if you don't need to, since it can lead to other problems.
A better approach is just to make the Fragment extend SupportMapFragment. Doing it this way, you don't even need a layout xml file.
Example:
public class MapView extends SupportMapFragment
implements OnMapReadyCallback {
private GoogleMap mMap;
private Marker marker;
public MapView() {
}
#Override
public void onResume() {
super.onResume();
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
if (mMap == null) {
getMapAsync(this);
}
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
setUpMap();
}
private void setUpMap() {
mMap.setMyLocationEnabled(true);
mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
mMap.getUiSettings().setMapToolbarEnabled(false);
}
}

Can you please try this way ?
<com.google.android.gms.maps.MapView
android:id="#+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Activity or Fragment:
private GoogleMap mMap;
private MapView mapView;
on onCreate():
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_map,container, false)
initializaMap(rootView, savedInstanceState);
return rootView;
}
on onResume()
#Override
public void onResume() {
if(mapView!=null){
mapView.onResume();
}
super.onResume();
}
on onDestroy()
#Override
public void onDestroy() {
if(mapView!=null){
mapView.onDestroy();
}
super.onDestroy();
}
on onLowMemory()
#Override
public void onLowMemory() {
if(mapView!=null){
mapView.onLowMemory();
}
super.onLowMemory();
}
Add new method:
private void initializaMap(View rootView, Bundle savedInstanceState){
MapsInitializer.initialize(getActivity());
switch (GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity())) {
case ConnectionResult.SUCCESS:
mapView = (MapView) rootView.findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
if (mapView != null) {
mMap = mapView.getMap();
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
UiSettings mUiSettings = mMap.getUiSettings();
mMap.setMyLocationEnabled(true);
mMap.animateCamera(CameraUpdateFactory.zoomTo(zoomLevel));
mUiSettings.setCompassEnabled(true);
mUiSettings.setMyLocationButtonEnabled(false);
mMap.setOnMarkerClickListener(this);
}
break;
case ConnectionResult.SERVICE_MISSING:
break;
case ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED:
break;
default:
}
}
Hope this will help you.

Related

OnMapReadyCallback not triggered when using Fragment

The onMapReady function is never called. It needs to be triggered for proper initializating of my GoogleMap.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
}
}
Should I inherit MapFragment instead of Fragment? Because I get another Error when I do: it returns a NullPointerException in MainActivity
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.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
public class MapsFragment extends Fragment implements OnMapReadyCallback {
private GoogleMap mMap;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.activity_maps, container, false);
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
}
}
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name=".fragment.MapsFragment"
android:id="#+id/maps_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent">
</fragment>
</LinearLayout>
activity_maps.xml
<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"
tools:context=".fragment.MapsFragment" />
Many thanks guys!
Update 1:
Added this to MapsActivity, but now MainActivity returns android.view.InflateException: Binary XML file line #6: Error inflating class fragment
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
SupportMapFragment supportMapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map);
supportMapFragment.getMapAsync(this);
}
Try This
public class MapsFragment extends Fragment implements OnMapReadyCallback {
private GoogleMap mMap;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View mView = inflater.inflate(R.layout.activity_maps, container, false);
SupportMapFragment mapFragment = ((SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map));
mapFragment.getMapAsync(this);
return mView ;
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
}
}
Your MapsFragment should request getMapAsync to load map then only onMapReady will be called.
public class MapsFragment extends Fragment implements OnMapReadyCallback
{
private View fragmentView;
private GoogleMap mMap;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState)
{
fragmentView = inflater.inflate(R.layout.activity_maps, container, false);
return fragmentView;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
SupportMapFragment mapFragment = (SupportMapFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap)
{
mMap = googleMap;
}
}
here is the correct, workings solution:
MapsFragment
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
public class MapsFragment extends SupportMapFragment {
private GoogleMap mapView;
private void initGoogleMap() {
getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap googleMap) {
mapView = googleMap;
}
});
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initGoogleMap();
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
private MapsFragment mapsFragment;
private void initializeMapsFragment() {
FragmentTransaction mTransaction = getSupportFragmentManager().beginTransaction();
mapsFragment = new MapsFragment();
SupportMapFragment supportMapFragment = mapsFragment;
mTransaction.add(R.id.google_maps_frame, supportMapFragment);
mTransaction.commit();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
initializeMapsFragment();
}
}
main_activity.xml, removed maps_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/google_maps_frame"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginBottom="-8dp"
android:layout_weight="0.2" >
</FrameLayout>
</LinearLayout>

Indoor maps are not appearing in a mapView in a Fragment

I have a google map app that is using a mapview in a fragment to display maps. This is working perfectly except that it doesn't display indoor maps.
I decided to create a stripped down version of my code to find the problem. It still exists :-(
In the documentation for indoor maps it says the following
SetIndoorEnabled
Sets whether indoor maps should be enabled. Currently, indoor maps can
only be shown on one map at a time and by default, this is the first map
added to your application. To enable indoor maps on another map, you
must first disable indoor maps on the original map. If you try to enable
indoor maps when it is enabled on another map, nothing will happen and
this will return false. When Indoor is not enabled for a map, all
methods related to indoor will return null, or false.
I can't see that I've enabled multiple maps but I'm wondering if somehow the use of a fragment confuses it.
Any help/advice would be greatly appeciated.
My MainActivity.java
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
Fragment map_fragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_2);
showTheMap();
}
public void showTheMap() {
map_fragment = new MapFragment();
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.map, map_fragment);
ft.commit();
}
}
The MapFrament.java
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.FrameLayout;
import com.google.android.gms.maps.CameraUpdate;
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.OnMapReadyCallback;
import com.google.android.gms.maps.model.LatLng;
public class MapFragment extends Fragment {
private MapView mapView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout parent = (FrameLayout) inflater.inflate(R.layout.fragment_map, container, false);
mapView = (MapView) parent.findViewById(R.id.mapfragment);
mapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap googleMap) {
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(-35.0176402, 138.5459909), 17);
googleMap.animateCamera(cameraUpdate);
}
}
);
mapView.onCreate(savedInstanceState);
return parent;
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onResume() {
mapView.onResume();
super.onResume();
}
#Override
public void onPause() {
super.onPause();
mapView.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}
activity_main_2.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
</android.support.design.widget.AppBarLayout>
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
class="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
</android.support.design.widget.CoordinatorLayout>
The fragment_map.xml
<FrameLayout 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/mapfragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center" />
</FrameLayout>
If you move the code to MainActivity it works perfectly. See code below
MainActivity.Java
public class MainActivity extends AppCompatActivity {
MapView mapView = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_1);
mapView = (MapView) findViewById(R.id.map);
mapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap googleMap) {
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(-35.0176402, 138.5459909), 17);
googleMap.animateCamera(cameraUpdate);
}
}
);
mapView.onCreate(savedInstanceState);
}
#Override
protected void onStart() {
super.onStart();
}
#Override
public void onResume() {
super.onResume();
mapView.onResume();
}
#Override
public void onPause() {
super.onPause();
mapView.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
#Override
protected void onStop() {
super.onStop();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
}
The activity_main_1 xml for this is ....
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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"
android:fitsSystemWindows="true"
tools:context="com.example.program.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
</android.support.design.widget.AppBarLayout>
<com.google.android.gms.maps.MapView
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center" />
</android.support.design.widget.CoordinatorLayout>
The following is a solution for my problem.
Declare myGoogleMap in the MainActivity
public static GoogleMap myGoogleMap = null;
In onMapReady add these lines as the first action to do
if (MainActivity.myGoogleMap != null) {
MainActivity.myGoogleMap.setIndoorEnabled(false);
googleMap.setIndoorEnabled(true);
MainActivity.myGoogleMap = googleMap;
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(-35.0176402, 138.5459909), 17);
MainActivity.myGoogleMap.animateCamera(cameraUpdate);
}
It seems as though getMapAsync is called twice and therefore 2 google maps are created, the second one is being displayed.
As indoor maps only appear on the first map you have to setIndoorEnabled to false for the first map and then setIndoorEnabled to true for the second one.
This seems dodgy to me.
Not sure if its a bug or my lack of understanding.

Is it possible to add a Button to GoogleMaps?

I am a bit confused whether or not it is possible to add a button to googlemaps. I tried to create a relative layout where i would put the fragment and a image button in the same layout but for some reason my app keeps on crashing. Here is what my XML looks like:
<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=".MapsActivity" >
<fragment
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.MapFragment" />
<ImageButton
android:id="#+id/theimagebutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/car"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"/>
</RelativeLayout>
And I get this Error java.lang.RuntimeException: Unable to resume activity java.lang.NullPointerException: Attempt to invoke virtual method 'com.google.android.gms.maps.GoogleMap com.google.android.gms.maps.SupportMapFragment.getMap()' on a null object reference
import android.content.Context;
import android.graphics.Color;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.widget.Toast;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;
import com.parse.ParseGeoPoint;
import com.parse.ParseObject;
public class MapsActivity extends FragmentActivity implements RoutingListener {
protected GoogleMap mMap;
protected LatLng start;
protected LatLng end;
/**
* This activity loads a map and then displays the route and pushpins on it.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
SupportMapFragment mMap = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
try {
setUpMapIfNeeded();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the map.
if (mMap == null) {
// Try to obtain the map from the SupportMapFragment.
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
// Check if we were successful in obtaining the map.
if (mMap != null) {
setUpMap();
}
}
}
/**
* This is where we can add markers or lines, add listeners or move the camera. In this case, we
* just add a marker near Africa.
* <p/>
* This should only be called once and when we are sure that {#link #mMap} is not null.
*/
private void setUpMap() {
// Enable MyLocation Layer of Google Map
mMap.setMyLocationEnabled(true);
// Get LocationManager object from System Service LOCATION_SERVICE
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// Create a criteria object to retrieve provider
Criteria criteria = new Criteria();
// Get the name of the best provider
String provider = locationManager.getBestProvider(criteria, true);
// Get Current Location
Location myLocation = locationManager.getLastKnownLocation(provider);
// set map type
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
// Get latitude of the current location
mMap.getUiSettings().setZoomControlsEnabled(true);
mMap.getUiSettings().setMyLocationButtonEnabled(true);
mMap.getUiSettings().setCompassEnabled(true);
mMap.getUiSettings().setRotateGesturesEnabled(true);
mMap.getUiSettings().setZoomGesturesEnabled(true);
Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
double longitude = location.getLongitude();
double latitude = location.getLatitude();
// Get longitude of the current location
// Create a LatLng object for the current location
LatLng latLng = new LatLng(latitude, longitude);
ParseObject parkingobject = new ParseObject("Kitchen");
parkingobject.put("username","Mike");
ParseGeoPoint point = new ParseGeoPoint(latitude,longitude); **THINK THE ERROR IS HERE**
parkingobject.put("Location", point);
// Show the current location in Google Map
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
// Zoom in the Google Map
//LatLng myCoordinates = new LatLng(latitude, longitude);
//CameraUpdate yourLocation = CameraUpdateFactory.newLatLngZoom(myCoordinates, 20);
//mMap.animateCamera(yourLocation);
// mMap.animateCamera(CameraUpdateFactory.zoomTo(20));
//mMap.addMarker(new MarkerOptions().position(new LatLng(latitude, longitude)).title("You are here!").snippet("Consider yourself located"));
LatLng fromLatLng = latLng;
start = latLng;
Routing routing = new Routing(Routing.TravelMode.DRIVING);
routing.registerListener(this);
routing.execute(start, end);
}
}
//map = fm.getMap();
#Override
public void onRoutingFailure() {
// The Routing request failed
}
#Override
public void onRoutingStart() {
// The Routing Request starts
}
#Override
public void onRoutingSuccess(PolylineOptions mPolyOptions, Route route) {
PolylineOptions polyOptions = new PolylineOptions();
polyOptions.color(Color.BLUE);
polyOptions.width(10);
polyOptions.addAll(mPolyOptions.getPoints());
mMap.addPolyline(polyOptions);
// Start marker
MarkerOptions options = new MarkerOptions();
options.position(start);
//options.icon(BitmapDescriptorFactory.fromResource(R.drawable.home));
mMap.addMarker(options);
// End marker
options = new MarkerOptions();
options.position(end);
options.icon(BitmapDescriptorFactory.fromResource(R.drawable.cars));
mMap.addMarker(options);
}
}
Can someone guide me in the right direction? Thanks in advance.
The main problem is that you're using getSupportFragmentManager() and you're not using a SupportMapFragment in your xml layout.
Replacing class="com.google.android.gms.maps.MapFragment" with class="com.google.android.gms.maps.SupportMapFragment" made it work for me.
xml layout (Note I just used drawable/common_signin_btn_icon_dark for the button image):
<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=".MapsActivity" >
<fragment
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment" />
<ImageButton
android:id="#+id/theimagebutton"
android:text="button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/common_signin_btn_icon_dark"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"/>
</RelativeLayout>
Default code generated by Android Studio:
public class MapsActivity extends FragmentActivity {
private GoogleMap mMap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
setUpMapIfNeeded();
}
#Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the map.
if (mMap == null) {
// Try to obtain the map from the SupportMapFragment.
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
// Check if we were successful in obtaining the map.
if (mMap != null) {
setUpMap();
}
}
}
private void setUpMap() {
mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
}
}
Result:
As #Evan Bashir pointed out in the comments this issue is not related to your layout.
You should use the onMapReady() callback to get a handle to the GoogleMap object.
First implement the callback to your Activity:
public class MainActivity extends FragmentActivity
implements RoutingListener, OnMapReadyCallback {
Find your MapFragment and set the callback in your onCreate():
MapFragment mapFragment = (MapFragment) getFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
Finally implement onMapReady() in your MainActivity:
#Override
public void onMapReady(GoogleMap map) {
mMap = map;
setUpMap();
}
This callback is triggered when the map is ready to be used, so you won't get null.

MapView getMap() returns null on Lollipop

Mapview.getmap going back empty under 19 version of Android ! MapView getMap() returns null on Lollipop. Version 22 also does not have a problem. Map opens and we can add markers. Why invoke the GetMap method returns null in the old version?
public class AnaActivity extends ActionBarActivity {
public static FragmentManager mFragmenManager;
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
..
mFragmenManager = getSupportFragmentManager();
}
...
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment"
/>
HaritaFragment.java
public class HaritaFragment extends Fragment {
GoogleMap mMap;
MapView mMapView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.map_activity, container, false);
mMapView = (MapView) rootView.findViewById(R.id.mapView);
mMapView.onCreate(savedInstanceState);
mMapView.onResume();
try {
MapsInitializer.initialize(getActivity().getApplicationContext());
} catch (Exception e) {
hataGoster(e.getMessage());
}
mMap = mMapView.getMap(); // **** return null on LOLLIPOPS Version
}
}
map_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.google.android.gms.maps.MapView
android:id="#+id/mapView"
class="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</RelativeLayout>
Try this:
MapsActivity.java
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
public class MapsActivity extends FragmentActivity {
private GoogleMap mMap; // Might be null if Google Play services APK is not available.
private MapFragment mapFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
setUpMapIfNeeded();
}
#Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
mapFragment = ((MapFragment) getFragmentManager().findFragmentById(R.id.map));
mapFragment.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
setUpMap();
}
});
}
private void setUpMap() {
mMap.setMyLocationEnabled(true);
mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
}
}
Layout:
<fragment 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" android:id="#+id/map" tools:context=".MapsActivity"
android:name="com.google.android.gms.maps.MapFragment" />

How to put Google Maps V2 on a Fragment using ViewPager

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?
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.
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" />
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();
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);
}
}
});
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" />
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);
}
}
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" />
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.
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.
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!
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;
}
}
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;
}
}
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);

Categories

Resources