Reputation: 988
I use in another fragment google maps that works fine. So when I had to do it for another fragment, inside the same app, I copy/paste the code and adapted the inflator and the findviewbyid. But onMapReady() is never called so googlemap stays null.
I've seen the MapView.onMapReady never called in Fragment for load Google Map in MapView case which looks similar to mine but I'd like to understand the "implements OnMapReadyCallback" mechanism.
What is the mechanism to call onMapReady? I suppose when the call to mapView.getMapAsync(this) happens?
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
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.OnMapReadyCallback;
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;
public class LocalisationMonitoringFragment extends Fragment implements OnMapReadyCallback {
private Context context;
private static View view;
private MapView mapView;
static private GoogleMap googleMap;
public LocalisationMonitoringFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
view = inflater.inflate(R.layout.localization_monitor, null);
mapView = (MapView) view.findViewById(R.id.loc_mapView);
mapView.onCreate(savedInstanceState);
mapView.onResume();
mapView.getMapAsync(this);
try {
MapsInitializer.initialize(getActivity().getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
return (view);
}
@Override
public void onMapReady(GoogleMap map) {
googleMap = map;
LatLng sydney = new LatLng(latitude, longitude);
googleMap.addMarker(new MarkerOptions().position(sydney).title("Marker Title").snippet("Marker Description"));
CameraPosition cameraPosition = new CameraPosition.Builder().target(sydney).zoom(12).build();
googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
in the layout file I have:
<com.google.android.gms.maps.MapView
android:id="@+id/loc_mapView"
android:layout_below="@id/loc_name_txt"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="20dp" />
Upvotes: 0
Views: 2204
Reputation: 2409
In my Fragment's xml file, I have used the following:
<com.google.android.gms.maps.MapView
android:id="@+id/googleMap"
android:layout_width="match_parent"
android:layout_height="match_parent" />
In the Fragment.kt file, I have used the following:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view: View = inflater.inflate(R.layout.fram_map_fragment, container, false)
initMap(view, savedInstanceState)
return view
}
private fun initMap(view: View?, savedInstanceState: Bundle?) {
mapView = view?.findViewById(R.id.googleMap)
mapView?.onCreate(savedInstanceState)
mapView?.getMapAsync(this)
}
override fun onMapReady(map: GoogleMap?) {
googleMap = map
googleMap?.moveCamera(
CameraUpdateFactory.newLatLngZoom(
LatLng(lat, lng),
17F
)
)
googleMap?.mapType = GoogleMap.MAP_TYPE_SATELLITE
googleMap?.setOnMapClickListener {
// Create Marker
drawMarkers(it)
}
}
override fun onResume() {
mapView?.onResume()
super.onResume()
}
override fun onPause() {
mapView?.onPause()
super.onPause()
}
override fun onDestroy() {
mapView?.onDestroy()
super.onDestroy()
}
override fun onLowMemory() {
mapView?.onLowMemory()
super.onLowMemory()
}
And it is working perfectly.
Upvotes: 0
Reputation: 3809
First of all, it's never a good idea to store a View
into a static
field. The same applies to your GoogleMap
variable.
Second, I don't see why you should call onResume()
right after you call onCreate(Bundle)
from your mapView
.
Maybe that onResume()
call may already be the issue.
About the life-cycle mechanism
It means (e.g.); the onPause()
method in your fragment should call the onPause()
method of the MapView
.
@Override protected void onPause() {
super.onPause();
this.mapView.onPause();
}
You should then implement other life-cycle methods with the same logic:
onDestroy()
onResume()
onLowMemory()
onSaveInstanceState()
onStop()
onCreate(Bundle)
Also, of course, if you haven't registered a Google Maps API Key, your Map will not show up. So make sure you also did that. You never know...
By looking at a project of mine, which feature a fully-working MapView
inside a Fragment
I see I had overridden the life-cycle methods in this way:
@Override protected void onPause() {
super.onPause();
if (this.mapView != null)
this.mapView.onPause();
}
Don't know if it's necessary in your case. I had a few cases in which the MapView
wasn't initialized and threw a NullPointerException
. Test without it, then if it's necessary add a null
check.
Moreover, I actually left out the following methods:
onSaveInstanceState()
onStop()
onCreate(Bundle)
They were all the cause of some crashes in my application, so I did not override them.
Still, implement it as the docs say. If you run into some issues, you may try what I did.
Moreover, in onCreateView(...)
I called
MapsInitializer.initialize(getContext());
before
this.mapView = (MapView) ...;
My onCreateView(...)
method looked like this.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
this.rootView = inflater.inflate(R.layout.fragment_location, container, false);
MapsInitializer.initialize(getContext());
this.mapView = (MapView) rootView.findViewById(R.id.map_view);
this.mapView.onCreate(savedInstanceState);
this.mapView.getMapAsync(this);
// initialize other UI elements.
return this.rootView;
}
Although I doubt it, the issues I mentioned above, may have happened because I used the android.support.v4.app.Fragment
version instead of the android.app.Fragment;
one.
Upvotes: 1