André Freitas
André Freitas

Reputation: 273

How get a reference to a GoogleMap object created in java?

I'm trying to get a reference to a GoogleMap object created java, and i don't know how to get this reference.

Here's my code:

        LinearLayout mapLayout = new LinearLayout(customToursActivity);
        mapLayout.setId(generateViewId(rootView));
        int mapLayoutHeight = Math.round(getResources().getDimension(R.dimen.custom_tour_list_map_size));
        mapLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, mapLayoutHeight));
        layout.addView(mapLayout);

        FragmentManager fm = getChildFragmentManager();
        SupportMapFragment supportMapFragment =  SupportMapFragment.newInstance();
        fm.beginTransaction().replace(mapLayout.getId(), supportMapFragment).commit();
        GoogleMap mMap = supportMapFragment.getMap();
        mMap.setMyLocationEnabled(true);

Here's the log i got:

01-23 17:09:54.168    3795-3795/abff.googlemapsappteste E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: abff.googlemapsappteste, PID: 3795
    java.lang.NullPointerException: Attempt to invoke virtual method 'void com.google.android.gms.maps.GoogleMap.setMyLocationEnabled(boolean)' on a null object reference
            at abff.googlemapsappteste.CustomToursList.createPlacemarksList(CustomToursList.java:458)
            at abff.googlemapsappteste.CustomToursList.onCreateView(CustomToursList.java:73)
            at android.support.v4.app.Fragment.performCreateView(Fragment.java:1789)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:955)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1138)
            at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:740)
            at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1501)
            at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:490)
            at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141)
            at android.support.v4.view.ViewPager.populate(ViewPager.java:1105)
            at android.support.v4.view.ViewPager.populate(ViewPager.java:951)
            at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1473)
            at android.view.View.measure(View.java:17637)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5536)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)
            at android.support.v7.internal.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:124)
            at android.view.View.measure(View.java:17637)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5536)
            at android.support.v7.internal.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:444)
            at android.view.View.measure(View.java:17637)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5536)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)
            at android.view.View.measure(View.java:17637)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5536)
            at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436)
            at android.widget.LinearLayout.measureVertical(LinearLayout.java:722)
            at android.widget.LinearLayout.onMeasure(LinearLayout.java:613)
            at android.view.View.measure(View.java:17637)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5536)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)
            at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2618)
            at android.view.View.measure(View.java:17637)
            at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2019)
            at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1177)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1383)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1065)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5901)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
            at android.view.Choreographer.doCallbacks(Choreographer.java:580)
            at android.view.Choreographer.doFrame(Choreographer.java:550)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:211)
            at android.app.ActivityThread.main(ActivityThread.java:5389)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1020)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:815)

Upvotes: 0

Views: 1720

Answers (2)

Mukesh Rana
Mukesh Rana

Reputation: 4091

There are couple of ways to do the same.

1). If you are targeting an application after API level 12, then you can simply make use of MapFragment instead of SupportMapFragment. Below is the sample code how you can add MapFragment to your Fragment and get reference to GoogleMap Object.

 Map mapFragment = MapFragment.newInstance();
 FragmentTransaction fragmentTransaction =
         getChildFragmentManager().beginTransaction();
 fragmentTransaction.replace(mapLayout.getId(), mapFragment).commit();

Then use getMapAsync() to set the callback on the fragment.

mapFragment.getMapAsync(this); // your fragment need to implement `OnMapReadyCallback`

Note: getMapAsync() must be called from the main thread, and the callback will be executed in the main thread. If Google Play services is not installed on the user's device, the callback will not be triggered until the user installs Play services.

Use the onMapReady(GoogleMap) callback method to get a handle to the GoogleMap object. The callback is triggered when the map is ready to be used. It provides a non-null instance of GoogleMap. You can use the GoogleMap object to set the view options for the map or add a marker, for example.

    @Override
public void onMapReady(GoogleMap map) {
      map.setMyLocationEnabled(true);
}

you can refer official documentation here

2). But if you are targeting an application earlier than API level 12 or you still want to use SupportMapFragment for some reason, you can further have two otpions.

a). Since the map initialization is async, you have to wait for SupportMapFragment.onCreateView() to be called which is basically after your Fragment onActivityCreated() and before onStart(). So if you add SupportMapFragment to transaction inside onActivityCreated() then you will have getMap() returning object in onStart() or onResume() (unless of course Google Play Services is not available). Below is the code sample.

public class MyFragment extends Fragment {

    private SupportMapFragment mSupportMapFragment;
    private GoogleMap mGoogleMap;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.layout_with_map, container, false);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        FragmentManager fm = getChildFragmentManager();
        mSupportMapFragment =  SupportMapFragment.newInstance();
        fm.beginTransaction().replace(mapLayout.getId(),mSupportMapFragment).commit();
    }

    @Override
    public void onResume() {
        super.onResume();
        if (mGoogleMap == null) {
            mGoogleMap = mSupportMapFragment.getMap();
        }
    }
}

If you face any IllegalStateException(an issue tracked in Google Bugs) just Override your Fragment onDetach()

@Override
public void onDetach() {
    super.onDetach();
    try {
        Field childFragmentManager = Fragment.class
                .getDeclaredField("mChildFragmentManager");
        childFragmentManager.setAccessible(true);
        childFragmentManager.set(this, null);
    } catch (NoSuchFieldException e) {
        throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}

b). You can Override the onActivityCreated() of the SupportMapFragment. For example.

public class MyFragment extends Fragment {

        private SupportMapFragment mSupportMapFragment;
        private GoogleMap mGoogleMap;

 @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.layout_with_map, container, false);
    mSupportMapFragment = new SupportMapFragment() {
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            mGoogleMap = mSupportMapFragment.getMap();
            if (mGoogleMap != null) {
               mGoogleMap.setMyLocationEnabled(true);
            }
        }
    };
    getChildFragmentManager().beginTransaction().replace(mapLayout.getId(), mSupportMapFragment).commit();;
    return view;   
   }
}

Upvotes: 1

patloew
patloew

Reputation: 1090

Since map initialization is async in current Play Services, I guess you call the getter before the GoogleMap object was set in the Fragment. You could use a custom Callback to be notified when the GoogleMap is ready, or you can use an event bus like Otto.

Upvotes: 1

Related Questions