Alexey Zakharov
Alexey Zakharov

Reputation: 25112

What is recommended way to use Google Map v2 inside fragment?

I want to add map inside fragment with custom layout.

  1. I can do it using ChildFragmentManager that will add SupportMapFragment. This approach im currently using. However it has disadvantage because child fragment transaction is asynchronous and its hard to guarantee that getMap won't return null.
  2. Another way is to extend SupportMapFragment store mapView from super onCreateView

    mapView = super.onCreateView(inflater, container, savedInstanceState);

    and insert it to inflated layout. Primary problem is that then fragment try to restore from saved state Google Maps SDK crushes internally.

Is there any other way to solve this problem. It would be great if somebody from Google Map team will recommend right approach because you haven't included anything like this to samples.

Upvotes: 17

Views: 4994

Answers (2)

Alex Vasilkov
Alex Vasilkov

Reputation: 6305

You can use MapView inside your Fragment (or Activity), this will allow you to use whatever layout you want.

I.e. your layout can look like this:

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

</FrameLayout>

You will also need to forward Fragment's lifecycle methods such as onCreate, onResume and so on to the MapView.

The only difference (seems to be a bug in Google Maps?) is that you also need to manually initialize Google Maps:

private void setUpMapIfNeeded() {
    if (mMap == null) {
        mMap = mMapView.getMap();
        if (mMap != null) {
            // Thought official docs says that it is not necessary to call
            // initialize() method if we got not-null GoogleMap instance from
            // getMap() method it seems to be wrong in case of MapView class.
            try {
                MapsInitializer.initialize(getActivity());
                setUpMap(mMap);
            } catch (GooglePlayServicesNotAvailableException impossible) {
                mMap = null;
            }
        }
    }
}

Upvotes: 3

Michael Celey
Michael Celey

Reputation: 12745

All FragmentTransactions are asynchronous. If you would like your transaction to happen immediately, you'll have to force them through like so:

getChildFragmentManager().beginTransaction.add(R.id.container, new MyMapFragment(), "MyMapFragment").commit();
getChildFragmentManager().executePendingTransactions();
/* getMap() should not return null here */

From the Android Developer Site:

After a FragmentTransaction is committed with FragmentTransaction.commit(), it is scheduled to be executed asynchronously on the process's main thread. If you want to immediately executing any such pending operations, you can call this function (only from the main thread) to do so. Note that all callbacks and other related behavior will be done from within this call, so be careful about where this is called from.

Returns
Returns true if there were any pending transactions to be executed.

Upvotes: 13

Related Questions