title: How do you use a Google MapView inside of a Fragment?
body: <h1>Desired Behavior</h1>
  
  <p>In case it affects any answers or suggestions, what I would like to ultimately see in this app is a navigation UI where one of the <code>Fragment</code> is a map.  I used a template to start with a navigation UI, which gave me several <code>Fragment</code>s, one for each tab.  Currently, I'm trying to use the Google API to put a <code>MapView</code> inside of one of those <code>Fragment</code>s.</p>
  
  <h1>Current Behavior</h1>
  
  <p>Generally, this isn't working (obviously).  I have everything up and running, but when I pull up the tab with the map in it, the map is blank.  Nothing crashes, and no errors are output:</p>
  
  <pre><code>I/Google Maps Android API: Google Play services client version: 12451000
  I/Google Maps Android API: Google Play services package version: 201516040
  D/NetworkSecurityConfig: No Network Security Config specified, using platform default
  I/DynamiteModule: Considering local module com.google.android.gms.googlecertificates:0 and remote module com.google.android.gms.googlecertificates:4
      Selected remote version of com.google.android.gms.googlecertificates, version &gt;= 4
  </code></pre>
  
  <h1>Other Details/Troubleshooting</h1>
  
  <p>I know that my API key works because I have another app in which the maps work as expected.  I doubt I need a second API key, but I looked anyway and since it wasn't overly obvious how to create a second API key, I think that hunch is correct.  Most of the code I'm using was copied from that working example; the primary difference is that other example uses a <code>SupportMapFragment</code> and it has a <code>class MapsActivity extends FragmentActivity</code>.  Here, since I don't really want to deal with nesting fragments, I'm trying to use a <code>MapView</code> inside that fragment.</p>
  
  <p>What bits of my code that weren't copied largely came from online sources.  None of what I've tried has produced better results.</p>
  
  <p><a href="https://stackoverflow.com/questions/44270958/mapview-inside-fragment">MapView inside fragment</a> is answering a different problem</p>
  
  <p><a href="https://stackoverflow.com/questions/31985046/creating-google-maps-v2-in-a-fragment-using-navigation-drawer">Creating google maps v2 in a fragment using Navigation Drawer</a> contains only things I already have</p>
  
  <p><a href="https://stackoverflow.com/questions/26174527/android-mapview-in-fragment">android MapView in Fragment</a> gave me the idea to use <code>MapsInitializer.initialize(this.getActivity());</code> but that didn't help</p>
  
  <p><a href="https://stackoverflow.com/questions/39585989/mapview-in-separate-fragment-android">Mapview in separate fragment android</a> has nothing new</p>
  
  <p><a href="https://stackoverflow.com/questions/51442253/how-do-i-solve-integrating-google-map-in-fragment-in-android">how do i solve integrating google map in fragment in android</a> uses a <code>Fragment</code> not a <code>MapView</code></p>
  
  <p>I also know that <code>onMapReady</code> is being called.  Inside of that, I move the camera and that subsequently calls <code>onCameraMoveStarted</code>.  However, it does not enter <code>onCameraMove</code> or <code>onCameraIdle</code>.</p>
  
  <h1>Code</h1>
  
  <p>This is the code as it is, which uses some of the ideas from the above links.  I tried to cut out anything that's unrelated (other fragments, etc)</p>
  
  <h3>AndroidManifest.xml</h3>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.example.retailtherapy"&gt;
  
      &lt;uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /&gt;
      &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /&gt;
      &lt;uses-permission android:name="android.permission.INTERNET" /&gt;
  
      &lt;application
          android:allowBackup="true"
          android:icon="@mipmap/ic_launcher"
          android:label="@string/app_name"
          android:roundIcon="@mipmap/ic_launcher_round"
          android:supportsRtl="true"
          android:theme="@style/AppTheme"&gt;
  
          &lt;meta-data
              android:name="com.google.android.geo.API_KEY"
              android:value="@string/google_maps_key" /&gt;
  
          &lt;activity
              android:name=".MainActivity"
              android:label="@string/app_name"
              android:windowSoftInputMode="stateVisible|adjustResize" &gt;
              &lt;intent-filter&gt;
                  &lt;action android:name="android.intent.action.MAIN" /&gt;
  
                  &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
              &lt;/intent-filter&gt;
          &lt;/activity&gt;
  
      &lt;/application&gt;
  
      &lt;uses-feature
          android:glEsVersion="0x00020000"
          android:required="true"/&gt;
  
  &lt;/manifest&gt;
  </code></pre>
  
  <h3>activity_main.xml</h3>
  
  <pre><code>&lt;androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      android:id="@+id/container"
      android:layout_width="match_parent"
      android:layout_height="match_parent"&gt;
  
      &lt;com.google.android.material.bottomnavigation.BottomNavigationView
          android:id="@+id/nav_view"
          app:menu="@menu/bottom_nav_menu" /&gt;
  
      &lt;fragment
          android:id="@+id/nav_host_fragment"
          android:name="androidx.navigation.fragment.NavHostFragment"
          app:defaultNavHost="true"
          app:navGraph="@navigation/mobile_navigation"
          tools:context=".MainActivity" /&gt;
  
  &lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;
  </code></pre>
  
  <h3>mobile_navigation.xml</h3>
  
  <pre><code>&lt;navigation xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      android:id="@+id/mobile_navigation"
      app:startDestination="@+id/navigation_map"&gt;
  
      &lt;fragment
          android:id="@+id/navigation_map"
          android:name="com.example.retailtherapy.ui.map.MapFragment"
          android:label="Map"
          tools:layout="@layout/fragment_map" /&gt;
  
  &lt;/navigation&gt;
  </code></pre>
  
  <h3>fragment_map.xml</h3>
  
  <pre><code>
  &lt;RelativeLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      tools:context=".ui.map.MapFragment" &gt;
  
      &lt;com.google.android.gms.maps.MapView
          android:id="@+id/googleMap"
          android:layout_width="match_parent"
          android:layout_height="match_parent" /&gt;
  
  &lt;/RelativeLayout&gt;
  </code></pre>
  
  <h3>MapFragment.java</h3>
  
  <pre><code>public class MapFragment extends Fragment implements OnMapReadyCallback, LocationListener {
  
      /*************************************************************************
       *
       * M E M B E R S
       *
       */
  
      // Location manager for getting current location
      private LocationManager mLocationManager = null;
  
      // The map object for reference for ease of adding points and such
      private GoogleMap mGoogleMap = null;
      private MapView mMapView = null;
  
      // The camera position tells us where the view is on the map
      private CameraPosition mCameraPosition = Constants.GetDefaultCameraPosition();
  
      // Current latitude and longitude of user
      private LatLng mCurrentLatLong = new LatLng(0.0, 0.0);
  
      // These are flags that allow us to selectively not move the camera and
      // instead wait for idle so the movement isn't jerky
      private boolean mCameraMoving = false;
      private boolean mPendingUpdate = false;
  
      /*************************************************************************
       *
       * F R A G M E N T
       *
       */
  
      public View onCreateView(@NonNull LayoutInflater inflater,
                               ViewGroup container, Bundle savedInstanceState) {
  
          super.onCreateView(inflater, container, savedInstanceState);
          View root = inflater.inflate(R.layout.fragment_map, container, false);
  
          // The google map...
          MapsInitializer.initialize(getActivity());
          mMapView = (MapView) root.findViewById(R.id.googleMap);
          mMapView.onCreate(savedInstanceState);
          mMapView.getMapAsync(this);
  
          // The required permissions...
          final String[] REQUIRED_PERMISSIONS = {
                  Manifest.permission.ACCESS_COARSE_LOCATION,
                  Manifest.permission.ACCESS_FINE_LOCATION,
                  Manifest.permission.INTERNET,
          };
          requestPermissions(REQUIRED_PERMISSIONS, 0);
  
          return root;
      }
  
      @Override
      public void onStart() throws SecurityException {
          super.onStart();
  
          // Location manager for getting info current location
          mLocationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
          mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, this);
      }
  
      @Override
      public void onResume() {
          super.onResume();
          mMapView.onResume();
      }
  
      @Override
      public void onStop() {
          super.onStop();
      }
  
      @Override
      public void onDestroyView() {
          super.onDestroyView();
          mMapView.onDestroy();
      }
  
      @Override
      public void onSaveInstanceState(Bundle outState) {
          super.onSaveInstanceState(outState);
          mMapView.onSaveInstanceState(outState);
      }
  
      @Override
      public void onLowMemory() {
          super.onLowMemory();
          mMapView.onLowMemory();
      }
  
      /*************************************************************************
       *
       * G O O G L E   M A P S
       *
       */
  
      @Override
      public void onMapReady(GoogleMap googleMap) {
          mGoogleMap = googleMap;
  
          // Assuming if here that we have permissions okay.  Dangerous sure
          // but I'm lazy...
          mGoogleMap.setMyLocationEnabled(true);
  
          // Store the location of the camera for UI purposes so we can go
          // back to where we were
          mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
              @Override
              public void onCameraMove() {
                  mCameraPosition = mGoogleMap.getCameraPosition();
              }
          });
          mGoogleMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
              @Override
              public void onCameraMoveStarted(int i) {
                  mCameraMoving = true;
              }
          });
          mGoogleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
              @Override
              public void onCameraIdle() {
                  mCameraMoving = false;
                  if (mPendingUpdate) {
                      centerCameraOnLocation(false);
                  }
              }
          });
  
          // Start with user centered in view
          centerCameraOnLocation(true);
      }
  
      /*************************************************************************
       *
       * L O C A T I O N
       *
       */
  
      @Override
      public void onLocationChanged(Location location) {
          // Store the current location so if we start auto-center but aren't
          // already, we know where to pan to
          LatLng newLatLng = new LatLng(location.getLatitude(), location.getLongitude());
          if (!newLatLng.equals(mCurrentLatLong)) {
              mCurrentLatLong = new LatLng(location.getLatitude(), location.getLongitude());
              centerCameraOnLocation(false);
          }
      }
  
      @Override
      public void onStatusChanged(String provider, int status, Bundle extras) {}
  
      @Override
      public void onProviderDisabled(String provider) {}
  
      @Override
      public void onProviderEnabled(String provider) {}
  
      /*************************************************************************
       *
       * M A P   C A M E R A
       *
       */
  
      /*
       * Updates the camera position based on current state.  If the camera is
       * already moving, then wait.
       */
      private void centerCameraOnLocation(boolean animate) {
          if (mGoogleMap == null) {
              return;
          }
  
          if (mCameraMoving) {
              mPendingUpdate = true;
              return;
          }
  
          // Get the CameraPosition to update to based on whether we are auto
          // centering or not.
          if (mCameraPosition == null) {
              mCameraPosition = Constants.GetDefaultCameraPosition();
          }
  
          // If this is the same as it was before, then don't reset it
          if (mCameraPosition.equals(mGoogleMap.getCameraPosition())) {
              return;
          }
  
          // Make the update so we can move the camera
          CameraUpdate cameraUpdate = CameraUpdateFactory.newCameraPosition(mCameraPosition);
  
          // Move the camera with or without animation.  The time we don't want
          // animation is when we're setting the position initially
          if (animate) {
              mGoogleMap.animateCamera(cameraUpdate);
          }
          else {
              mGoogleMap.moveCamera(cameraUpdate);
          }
          mPendingUpdate = false;
      }
  }
  </code></pre>