Android Maps V2 MapView inside custom fragment (NPE)
Solution 1
I succeeded in including a MapView (v2) in a custom Fragment itself embedded in a ViewPager. In my case, the MapView is included in the Fragment layout file. I have had to call lifecycle methods on MapView (onCreate()
called onCreateView()
from the Fragment), and to call manually MapsInitializer.initialize(context)
to avoid a NullPointerException
from class BitmapDescriptorFactory (to get the bitmap for markers). This last trick is strange, and I don't know why the Map system isn't properly initialized itself without this call, maybe it's just a bug in the current version ...
In my case I haven't had any NullPointerException
in onResume()
or onDestroy()
.
Solution 2
I struggled a bit with PoPy's answer but in the end I managed it and here is what I came up with. Probably this is helpful to others which will also come across this issue:
public class MyMapFragment extends Fragment {
private MapView mMapView;
private GoogleMap mMap;
private Bundle mBundle;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View inflatedView = inflater.inflate(R.layout.map_fragment, container, false);
try {
MapsInitializer.initialize(getActivity());
} catch (GooglePlayServicesNotAvailableException e) {
// TODO handle this situation
}
mMapView = (MapView) inflatedView.findViewById(R.id.map);
mMapView.onCreate(mBundle);
setUpMapIfNeeded(inflatedView);
return inflatedView;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBundle = savedInstanceState;
}
private void setUpMapIfNeeded(View inflatedView) {
if (mMap == null) {
mMap = ((MapView) inflatedView.findViewById(R.id.map)).getMap();
if (mMap != null) {
setUpMap();
}
}
}
private void setUpMap() {
mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
}
@Override
public void onResume() {
super.onResume();
mMapView.onResume();
}
@Override
public void onPause() {
super.onPause();
mMapView.onPause();
}
@Override
public void onDestroy() {
mMapView.onDestroy();
super.onDestroy();
}
}
And here is the corresponding res/layout/map_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/map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
You can omit the RelativeLayout
(and move the xmlns declartion up to your new root element, in this case the com.google.android.gms.maps.MapView
) if you have just one element in your layout like in this example.
Related videos on Youtube
dnkoutso
Updated on June 19, 2020Comments
-
dnkoutso almost 4 years
I do not want to use or extend
SupportMapFragment
orMapFragment
. I have my own base class with a bunch of code in it.The documentation clearly states that when someone uses
MapView
by itself, all corresponding lifecycle methods (onCreate()
onResume()
etc.) should be called.Most of the lifecycle methods in a
Fragment
are similar to anActivity
but when I switch back and forth between myFragment
I eventually get an obfuscated NPE inonDestroy()
or inonResume()
methods.All the samples provided use an
Activity
with aMapView
but not a customFragment
.Has someone done that already? Can you provide sample code of a
MapView
in your ownFragment
class? -
PoPy over 11 yearsHere are some details about MapsInitializer.initialize(context) from the official documentation: BitmapDescriptorFactory MapsInitializer
-
dnkoutso over 11 yearsclear I do have a Map object already but for some reason the exception is still thrown. It ended up working when I added this static ugly call.
-
Sébastien BATEZAT about 11 years@PoPy I'm trying to do the same as yourself (i.e : including mapView in a viewPager), but how do you do to keep mapView state (markers, position, zoom, ...). My state is lost when I go from page 1 (with map) to page 3, and return to page 1 !
-
Sébastien BATEZAT about 11 yearsThanks for your solution, it helped me. However, are you using this in a view pager ? Because I have a problem with this solution and a view pager. I don't know how to keep map state (see my comment on PoPy's answer for more details). Could you help me ?
-
Hesam about 11 yearsVery useful, Thanks Jens ;)
-
Khobaib about 11 years@jens thanx for the code, it works for the first fragment of my pager but when I swipe to 2nd fragment, the MapView shows nothing - it's like there was nothing in that frame. FYI, the fragment transactions are done in the parent fragment's
onCreateView
method. Another issue I have found - I have implementedsetOnMapClickListener
for the GoogleMap object but it seems all the clicks are not handled properly. It gets some of the clicks, not all. Don't know what happens here. -
Khobaib about 11 yearsUpdate - It seems that we have to call with
getChildFragmentManager()
from the parent fragment instead ofgetFragmentManager()
to avoid the issue that map comes in only one fragment. But while swipe in pager, I am getting some NullPointerException. -
PoPy about 11 years@Sebastien I haven't tried to save the state for the moment, so sorry but i can't help you on this
-
pvshnik over 10 yearsThanks for your implementation. I've noticed one issue. When restoring this map fragment from backstack, map camera position is lost. In my current implementation I use OnCameraChangeListener to save camera position each time it changes in fragment instance variable. When restoring fragment from backstack, I check this instance variable and if it is not null, move map camera to this saved position.
-
YuDroid almost 10 yearsThen how to add/use this MyMapFragment in my Activity? Can you please provide the complete example? I want to add mapview dynamically and moreover want to set width and height of mapview based on screen width and height. Please guide me for this..
-
Jens Kohl almost 10 years@YuDroid You should create a new question here on SO for that. Because that's out of scope of the OP.
-
Pijusn almost 10 years@Sebastien I believe MapView.onSaveInstaceState method is for the problem you are having.
-
laaptu almost 10 years@martyonair: Where have I called its twice? I have said at Activity or Fragment where you are using it. Please read it nicely and then only downvote
-
Marcel Bro over 9 years@laaptu Where did you initialize
mapView
? -
laaptu over 9 years@anoniim You can initialize either on
Activity
orFragment
,wherever you are using it -
Marcel Bro over 9 years@pvshnik What callback do you use for restoring fragment from backstack, please?
-
Marcel Bro over 9 years@laaptu I mean what method? Can't see it in your code snippet.
-
laaptu over 9 years@anoniim You can add like
findViewById(R.id.yourgivenid)
onActivity
onCreate()
after settingsetContentView
or onFragment
onCreateView
-
mmathieum over 9 yearsI had to call
MapView.onDestroy()
and clear theMapView
reference insideFragment.onDestroyView()
or else the resumed fragment was showing an empty gray map (kinda make sense since callingMapView.onCreate()
insideFragment.onCreateView()
).