Android – Google map blank even though onMapReady is called and GoogleMap is not null

I’m aware there are some questions around blank maps but the answer is always an API Key issue. I know that’s not the problem because it works fine if I just use the standard MapsActivity template, with the following running from inside an Activity:

SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                 .findFragmentById(R.id.map);
mapFragment.getMapAsync(this);

And the Activity layout as follows:

<FrameLayout android:id="@+id/container_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@id/my_toolbar"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <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=".MapsActivity" />

The problem occurs when I try to have a generic host Activity (for the purpose of a single Activity architecture), which requires me to create a Fragment (instead of an Activity) from which to call the map logic. When I do this, I get a blank screen instead of a map – but the logs show the GoogleMap object is not null and that the onMapReady callback is called. The app doesn’t crash and I don’t see any enlightening errors. Here’s my code…

fragment_map.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MapFragment">

    <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/mapSubFragment"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MapFragment" />

</FrameLayout>

MapFragment.java

public class MapFragment extends Fragment implements OnMapReadyCallback, GoogleMap.OnInfoWindowClickListener {
    private GoogleMap mMap;

    public MapFragment() {
        //Not sure why this is necessary, boilerplate from Navigation editor
    }

    public static MapFragment newInstance() {
        //Not sure why this is necessary, boilerplate from Navigation editor
        MapFragment fragment = new MapFragment();
        return fragment;
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_map, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {    
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager()
                .findFragmentById(R.id.mapSubFragment);
        Log.i("Code", String.valueOf(R.id.mapSubFragment));
        mapFragment.getMapAsync(this);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        Log.i("Code", String.valueOf(mMap == null));

        //Check if user has location permissions granted
        setupMap();
    }
    }

And then the host Actvity…

NavHostActivity.xml

public class NavHostActivity extends AppCompatActivity {

    private NavController navController;

    //Methods go here to inflate the toolbar
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_nav_host);

        navController = Navigation.findNavController(this, R.id.nav_host_fragment);

        Toolbar toolbar = findViewById(R.id.my_toolbar);
        setSupportActionBar(toolbar);

    }

    @Override
    public boolean onSupportNavigateUp() {
        // Allows NavigationUI to support proper up navigation or the drawer layout
        // drawer menu, depending on the situation.
        return navController.navigateUp();

    }
}

The layout for this host activity…

activity_nav_host.xml

<?xml version="1.0" encoding="utf-8"?>
<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=".NavHostActivity">

    //Toolbar stuff goes here

    <fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"

        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />


</RelativeLayout>

And finally my manifest contains this:

<meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="@string/google_maps_key" />

Thanks for any help, I’m stumped!

Answer

Oh Lordy, I have seen my error. Looks like I copied the xml for my activity_host_fragment.xml from the Google getting started documentation for Navigation.

For some reason that includes this:

android:layout_width="0dp"
android:layout_height="0dp"

I changed ‘0dp’ to match_parent and the map shows up. Looks like everything was working but for an infinitesimally small fragment.

I’ll leave this question here just in case anyone else copies blindly from that documentation or is interested in the code for a Map Fragment called from a Fragment (I couldn’t find any walkthroughs for that).

Leave a Reply

Your email address will not be published. Required fields are marked *