How do I know the map is ready to get used when using the SupportMapFragment?

In the onCreate method, I am making use of the SupportMapFragment to show a map.

    SupportMapFragment fragment = new SupportMapFragment();
    getSupportFragmentManager().beginTransaction()
            .add(android.R.id.content, fragment).commit();

In conjunction to this, I would like to add a marker. The problem is when the call to getMap is null, when can I try again? Is there an event I can register for or is my approach in and of itself wrong?

    mMap = ((SupportMapFragment)(getSupportFragmentManager().findFragmentById(R.id.map))).getMap();
    if(mMap == null)
        //what do I do here?

The map is in fact displaying on the phone however I appear to be having no luck in obtaining the reference to add markers.

UPDATE:

The reason I was creating the SupportMapFragment via the constructor is because the typical setContentView was crashing and did not work. This put me in the predicament where I could not obtain my reference in the onCreate method since I was in fact creating the SupportMapFragment at that time. In further investigation, it appears my setContentView issue was a byproduct of not having both the Google-play-services jar AND the module/src set up as part of the overall project. Upon doing BOTH of these, setContentView now works and I can obtain the reference via getMap() as I would expect.

lots.xml...

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+id/map"
          android:name="com.google.android.gms.maps.SupportMapFragment"
          android:layout_width="match_parent"
          android:layout_height="match_parent" />

LotsActivity.java...

public class LotsActivity extends FragmentActivity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.lots);

        GoogleMap mMap;
        mMap = ((SupportMapFragment)(getSupportFragmentManager().findFragmentById(R.id.map))).getMap();
        if(mMap == null)
            //this should not occur now
    }

EDIT: getMap is deprecated now

The problem is when the call to getMap is null, when can I try again?

That depends upon the nature of the problem.

If you set up the SupportMapFragment via the <fragment> element in the layout, you can call getMap() successfully in onCreate(). But, if you create the SupportMapFragment via the constructor, that's too soon -- the GoogleMap does not yet exist. You can extend SupportMapFragment and override onActivityCreated(), as getMap() is ready by then.

However, getMap() can also return null for a bigger problem, such as Google Play Services not being installed. You would need to use something like GooglePlayServicesUtil.isGooglePlayServicesAvailable() to detect this condition and deal with it however you wish.


I ended up extending the SupportMapFragment class and using a callback. The code is here:

public class MySupportMapFragment extends SupportMapFragment {

public MapViewCreatedListener itsMapViewCreatedListener;

// Callback for results

public abstract static class MapViewCreatedListener {
    public abstract void onMapCreated();
}

@Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = super.onCreateView(inflater, container, savedInstanceState);
    // Notify the view has been created
    if( itsMapViewCreatedListener != null ) {
        itsMapViewCreatedListener.onMapCreated();
    }
    return view;
}
}

I would rather have used an interface and override the onAttach(activity) method, but in my case, I didn't want the callback to go back to my MainActivity. I wanted it to return to an instance of Fragment. (The GoogleMap was essentially a fragment inside a fragment) I setup the callback and programmatically loaded the map with this. I would like to have set itsMapViewCreatedListener inside the constructor of MySupportMapFragment, but using anything other than parameterless constructors is discouraged.

itsMySupportMapFragment = new MySupportMapFragment();
MapViewCreatedListener mapViewCreatedListener = new MapViewCreatedListener() {
    @Override
    public void onMapCreated() {
        initPlacesGoogleMapCtrl();
    }
};
itsMySupportMapFragment.itsMapViewCreatedListener = mapViewCreatedListener;
FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.mapFragmentContainer, itsMySupportMapFragment);
transaction.addToBackStack(null);
transaction.commit();

And then, when I got the call back, I could get the map; no more null!

public void initPlacesGoogleMapCtrl() {
    // Map ready, get it.
    GoogleMap googleMap = itsMySupportMapFragment.getMap();
    // Do what you want...
}

I would comment on CommonsWare's answer but I don't have enough rep for that. Anyways, I was also having this problem that getMap() would return null in onActivityCreated. My setup is this: I have MainActivity that contains a fragment. In the onCreateView method of that fragment I created the SupportMapFragment and then added it to the fragment via the childFragmentManager. I kept reference to the SupportMapFragment and expected it to give me the map in onActivityCreated which it did not. The solution to that problem was to override the onActivityCreated of the SupportMapFragment but not the parent fragment. I did it like this in onCreateView:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_location, container, false);
    mMapFragment = new SupportMapFragment() {
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            mMap = mMapFragment.getMap();
            if (mMap != null) {
                setupMap();
            }
        }
    };
    getChildFragmentManager().beginTransaction().add(R.id.framelayout_location_container, mMapFragment).commit();
return v;   
}

Last month (December 2014) Google gave official solution for this problem. In newest (6.5) Google Play Services :

The getMap() method in MapView and MapFragment is now deprecated in favor of the new getMapAsync() method.

With getMapAsync(OnMapReadyCallback callback) you can set up listener for when GoogleMap is ready. It is passed in callback and it is provided to be not-null.

Google provided sample code for this:

public class MainActivity extends FragmentActivity
    implements OnMapReadyCallback {
...
}

and when initializing fragment:

MapFragment mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);

when map is ready, you callback will be called

@Override
public void onMapReady(GoogleMap map) {
    map.addMarker(new MarkerOptions()
        .position(new LatLng(0, 0))
        .title("Marker"));
}