narb
narb

Reputation: 988

using google map in a fragment: onMapReady is never called

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

Answers (2)

eyal
eyal

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

payloc91
payloc91

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.Fragmentversion instead of the android.app.Fragment; one.

Upvotes: 1

Related Questions