MapView.onMapReady never called in Fragment for lo

2020-03-03 07:31发布

I'll try to show a map in my Android application on a fragment named RoeteFragment. If I debug my code I see that the method onMapReady is never called so that the map will not load.

The fragment implements OnMapReadyCallback like needed and in the onCreateView I get the MapView and call getMapAsync. If I place a breakpoint on that method, it will always been hit, the breakpoint inside onMapReady never been hit. There is no exception thrown.

I've also a valid Google Maps API key in the file res/values/google_maps_api.xml.

Here is my code:

<?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:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/map" />

</RelativeLayout>
public class RoeteFragment extends Fragment implements OnMapReadyCallback {

    private MapView mapView;
    private static Roete _roete;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_roete, container, false);
        mapView = (MapView) view.findViewById(R.id.map);
        mapView.getMapAsync(this);
        return view;
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {

        if (_roete != null && _roete.getAankomstLocatie() != null && _roete.getVertrekLocatie() != null) {
            LatLng aankomst = new LatLng(_roete.getAankomstLocatie().getLatitude(), _roete.getAankomstLocatie().getLongitude());
            googleMap.addMarker(new MarkerOptions().position(aankomst).title("aankomst"));
            googleMap.moveCamera(CameraUpdateFactory.newLatLng(aankomst));

            LatLng vertrek = new LatLng(_roete.getVertrekLocatie().getLatitude(), _roete.getVertrekLocatie().getLongitude());
            googleMap.addMarker(new MarkerOptions().position(vertrek).title("vertrek"));
            googleMap.moveCamera(CameraUpdateFactory.newLatLng(vertrek));
        }
    }

    public static Fragment newInstance() {
        return new RoeteFragment ();
    }

    public static Fragment newInstance(Roete roete) {
        _roete = roete;
        return newInstance();
    }
}

Could you file the bug in my code?

6条回答
劳资没心,怎么记你
2楼-- · 2020-03-03 07:44

Read MapView documentation. Especially:

Users of this class must forward all the life cycle methods from the Activity or Fragment containing this view to the corresponding ones in this class. In particular, you must forward on the following methods:

  • onCreate(Bundle)
  • onResume()
  • onPause()
  • onDestroy()
  • onSaveInstanceState()
  • onLowMemory()
查看更多
霸刀☆藐视天下
3楼-- · 2020-03-03 07:44

Try to use support map fragment. It will work in fragments also. https://developers.google.com/android/reference/com/google/android/gms/maps/SupportMapFragment#developer-guide

For camera and zoom level check this -https://developers.google.com/maps/documentation/android-api/views#introduction

Try this and if it help accept it as answer.

查看更多
4楼-- · 2020-03-03 07:53

You should notice this from the doc:

When using the API in fully interactive mode, users of the MapView class must forward all the activity life cycle methods to the corresponding methods in the MapView class. Examples of the life cycle methods include onCreate(), onDestroy(), onResume(), and onPause().

When using the MapView class in lite mode, forwarding lifecycle events is optional, except for the following situations:

  • It is mandatory to call onCreate(), otherwise no map will appear.

  • If you wish to show the My Location dot on your lite mode map and use the default location source, you will need to call onResume() and onPause(), because the location source will only update between these calls. If you use your own location source, it's not necessary to call these two methods.

So, you are missing mapView.onCreate(mapViewBundle) in the onCreateView, and since your map is in fully interactive mode, you must take care of the entire lifecylce, something like this:

public class RoeteFragment extends Fragment implements OnMapReadyCallback {

    private static final String MAPVIEW_BUNDLE_KEY = "MapViewBundleKey";

    private MapView mapView;
    private static Roete _roete;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_roete, container, false);
        mapView = (MapView) view.findViewById(R.id.map);

        // *** IMPORTANT ***
        // MapView requires that the Bundle you pass contain ONLY MapView SDK
        // objects or sub-Bundles.
        Bundle mapViewBundle = null;
        if (savedInstanceState != null) {
            mapViewBundle = savedInstanceState.getBundle(MAPVIEW_BUNDLE_KEY);
        }
        mapView.onCreate(mapViewBundle);
        mapView.getMapAsync(this);
        return view;
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {

        if (_roete != null && _roete.getAankomstLocatie() != null && _roete.getVertrekLocatie() != null) {
            LatLng aankomst = new LatLng(_roete.getAankomstLocatie().getLatitude(), _roete.getAankomstLocatie().getLongitude());
            googleMap.addMarker(new MarkerOptions().position(aankomst).title("aankomst"));
            googleMap.moveCamera(CameraUpdateFactory.newLatLng(aankomst));

            LatLng vertrek = new LatLng(_roete.getVertrekLocatie().getLatitude(), _roete.getVertrekLocatie().getLongitude());
            googleMap.addMarker(new MarkerOptions().position(vertrek).title("vertrek"));
            googleMap.moveCamera(CameraUpdateFactory.newLatLng(vertrek));
        }
    }

    public static Fragment newInstance() {
        return new RoeteFragment ();
    }

    public static Fragment newInstance(Roete roete) {
        _roete = roete;
        return newInstance();
    }

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

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

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Bundle mapViewBundle = outState.getBundle(MAPVIEW_BUNDLE_KEY);
        if (mapViewBundle == null) {
            mapViewBundle = new Bundle();
            outState.putBundle(MAPVIEW_BUNDLE_KEY, mapViewBundle);
        }

        mapView.onSaveInstanceState(mapViewBundle);
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        mapView.onDestroy();
    }
}
查看更多
来,给爷笑一个
5楼-- · 2020-03-03 07:55

The map fragment is part of a layout you inflate to another fragment (let's call it parent). The inflated fragment becomes a child fragment NOT of the activity BUT of the parent fragment. You have to ask the parent fragment's child fragment manager:

Note: Just extend simple fragment public class MapsFragments extends Fragment implements OnMapReadyCallback {} XML file

<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="net.elektrasoft.Test.MapsFragments" />

and

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    Log.d("check","onCreateView");
    // Inflate the layout for this fragment
    View view= inflater.inflate(R.layout.fragment_maps_fragments, container, false);
    // Gets the MapView from the XML layout and creates it
    final SupportMapFragment myMAPF = (SupportMapFragment) getChildFragmentManager()
            .findFragmentById(R.id.map);
    myMAPF.getMapAsync(this);
    return  view;
}`
查看更多
做自己的国王
6楼-- · 2020-03-03 07:56

Just let you know first this. I am using Google Map fragment as a child fragment inside an other fragment where GoogleMapFragment extents com.google.android.gms.maps.SupportMapFragment

I was using this piece of code in GoogleMapFragment in onCreateView, you can use in onStart as well. When onMapReady was not calling

MapFragment mapFragment = new MapFragment();
mapFragment.getMapAsync(new OnMapReadyCallback() {
      @Override
      public void onMapReady(GoogleMap map) {
           mCallback.onMapReady(map);
      }
});

I just removed this

MapFragment mapFragment = new MapFragment();

and start calling like this

this.getMapAsync(new OnMapReadyCallback() {
      @Override
      public void onMapReady(GoogleMap map) {
           Log.i(TAG, "onMapReady: onCreateView");
           mCallback.onMapReady(map);
       }
 });

I hope this might help someone.

查看更多
放荡不羁爱自由
7楼-- · 2020-03-03 08:02

By a comment from @androidnoobdev where he said to use SupportMapFragment, I've update the code in my layout file to this:

<?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">

     <fragment
        class="com.google.android.gms.maps.SupportMapFragment"
        android:layout_height="match_parent"
        android:layout_width="match_parent"/>

</RelativeLayout>

Update Removed MapView b'z not required after support fragment.

Thanks to @androidnoobdev

查看更多
登录 后发表回答