29

I'm using Google Maps API V2 in an activity wih drop down navigation where the map is on the second position.

I'm adding the map pragmatically like:

mMapFragment = supportMapFragment.newInstance();
getSupportFragmentManager()
        .beginTransaction()
        .replace(R.id.placeHolder, mMapFragment, TAG_MAP)
        .commit(); 

I want to get the GoogleMap ovject, as the documentation https://developers.google.com/maps/documentation/android/map say it should be done with mMapFragment.getMap(), but it returns null.

according to http://developer.android.com/reference/com/google/android/gms/maps/SupportMapFragment.html it returns null if the Fragment hasn't gone through the onCreateView lifecycle event.

how can I know whenever the fragment is ready ?

EDIT: I found this How do I know the map is ready to get used when using the SupportMapFragment?

Overriding onActivityCreated seems like a solution, but then I'll have to instantiate the fragment through a constructor and not with newInstance(), does it make any difference ?

Community
  • 1
  • 1
Gal Ben-Haim
  • 17,433
  • 22
  • 78
  • 131

4 Answers4

49

My preferred method is to use a callback to get a signal from a Fragment. Also, this is the recommended method proposed by Android at Communicating with the Activity

For your example, in your Fragment, add an interface and register it.

public static interface OnCompleteListener {
    public abstract void onComplete();
}

private OnCompleteListener mListener;

public void onAttach(Context context) {
    super.onAttach(context);
    try {
        this.mListener = (OnCompleteListener)context;
    }
    catch (final ClassCastException e) {
        throw new ClassCastException(context.toString() + " must implement OnCompleteListener");
    }
}

Now implement this interface in your Activity

public class MyActivity extends FragmentActivity implements MyFragment.OnCompleteListener {
    //...

    public void onComplete() {
        // After the fragment completes, it calls this callback.
        // setup the rest of your layout now
        mMapFragment.getMap()
    }
}

Now, whatever in your Fragment signifies that it's loaded, notify your Activity that it's ready.

@Override
protected void onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    // create your fragment
    //...

    // signal that you're done and tell the Actvity to call getMap()
    mListener.onComplete();
}

EDIT 2017-12-05 onAttach(Activity activity) is deprecated, use onAttach(Context context) instead. Code above adjusted.

Jenever
  • 500
  • 5
  • 17
Kirk
  • 16,182
  • 20
  • 80
  • 112
2

In addition to Kirk's answer: since public void onAttach(Activity activity) is deprecated you can now simply use:

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    Activity activity;

    if (context instanceof Activity){

        activity=(Activity) context;

        try {
            this.mListener = (OnCompleteListener)activity;
        } catch (final ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnCompleteListener");
        }
    }
}

The rest remains the same... One might want to use (Fragment sender) as a parameter though and always pass this.

Community
  • 1
  • 1
Rok Jarc
  • 18,765
  • 9
  • 69
  • 124
1

If you want to do it without any listener:

Add Fragment with a TAG

 supportFragmentManager
                .beginTransaction()
                .add(R.id.pagerContainer, UniversalWebViewFragment.newInstance(UniversalWebViewFragment.YOUTUBE_SERACH_URL+"HD trailers"), 
                "UniversalWebView")
                .disallowAddToBackStack()
                .commit()

Create a public method in Hosting Activity class which you want to call after fragment is loaded. Here I am calling back a method of my fragment for example

public fun loadURL() {
        val webViewFragment = supportFragmentManager
                              .findFragmentByTag("UniversalWebView") 
                               as UniversalWebViewFragment

        webViewFragment.searchOnYoutube("Crysis Warhead")
    }

Now inside onViewCreated Method of your fragment you can simply call that public method of Host activity like this:

    (activity as HomeActivity ).loadURL()
Hitesh Sahu
  • 41,955
  • 17
  • 205
  • 154
0

I'm not sure I'm completely understanding your issue, but I have a similar setup where I'm using a navigation drop down menu. Here's what works for me:

1.) Load the fragment from an xml file and call setupMapIfNeeded()

SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.basicMap);

setUpMapIfNeeded();

Here is the xml file for reference:

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

2.) Then setup the map (for details of isGoogleMapsInstalled(), see this question)

    private void setUpMapIfNeeded() 
    {
    // Do a null check to confirm that we have not already instantiated the map.
    if (mMap == null) 
    {
        // Try to obtain the map from the SupportMapFragment.
        mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.basicMap)).getMap();
        // Check if we were successful in obtaining the map.
        if(isGoogleMapsInstalled())
        {
            if (mMap != null) 
            {
                mMap.setOnCameraChangeListener(getCameraChangeListener());
                mMap.setInfoWindowAdapter(new MyCustomInfoWindowAdapter(this));
            }
        }
        else
        {
            MapConstants.showDialogWithTextAndButton(this, R.string.installGoogleMaps, R.string.install, false, getGoogleMapsListener());
        }
    }
    }

3.) Make sure you also call setUpMapIfNeeded() from onResume():

public void onResume()
{
    super.onResume();

    setUpMapIfNeeded();
}
Community
  • 1
  • 1
DiscDev
  • 38,652
  • 20
  • 117
  • 133