findFragmentById for SupportMapFragment returns null in Android Studio
Asked Answered
N

4

43

Recently I migrated a project from Eclipse to Android Studio. Everything is setup and working fine except for my one fragment which uses a SupportMapFragment. The below findFragmentById (which worked when building in Eclipse) is now returning null :(

public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    SupportMapFragment m = ((SupportMapFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.safety_map));

snippet of xml...

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:map="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical" >

     <fragment
         android:id="@+id/safety_map"
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
         android:layout_marginBottom="40dp"
         map:cameraTargetLat="@string/livesafe_latitude"
         map:cameraTargetLng="@string/livesafe_longitude"
         map:uiZoomControls="false"
         class="com.google.android.gms.maps.SupportMapFragment"/>

Here are my dependencies in my build.gradle:

 dependencies {
    //google analytics
    compile 'com.google.apis:google-api-services-analytics:v3-rev103-1.19.0'
    //support library for api 10
    compile 'com.android.support:support-v4:21.0.0'
    //google play services
    compile 'com.google.android.gms:play-services:6.1.11'
    compile project(':facebook')
    compile files('libs/android-support-multidex.jar')
    compile files('libs/aws-android-sdk-1.6.0-debug.jar')
    compile files('libs/FlurryAnalytics_3.3.2.jar')
 }

I haven't changed any code in the xml file or the Fragment class that previously worked in Eclipse.

Nikolos answered 27/10, 2014 at 21:27 Comment(4)
what is lsActivity? Could you try getActivity() instead?Uri
tried with getActivity() instead but no luck.... lsActivity is just used bc all my activities extends a Common and this is just so I don't have to typecast all over the place. lsActivity = (MyActivity) getActivity(); edited my question to avoid that confusion for othersNikolos
do this sir, just a callback test.. copy that very code and put it in onresume() of your fragment lifeclycle.. if it does not return null, well, it will be a callback lil problem, if it does happen, call it straight from your oncreatview method and get the id from the inflated layout..directly.. hope it helps you..Payable
OK moving into onResume() results in null as well. Could you be more specific with "get the id from the inflated layout directly"?Nikolos
D
175

Judging by the fact that you're overriding Fragment.onActivityCreated(), I take it that your layout containing the map fragment is the layout for your Fragment. In that case, the SupportMapFragment is a child fragment of your hosting Fragment. When you attempt to retrieve it, you're using the Activity FragmentManager. You should instead use your Fragment's FragmentManager:

For example, this:

SupportMapFragment m = ((SupportMapFragment) getActivity()
        .getSupportFragmentManager().findFragmentById(R.id.safety_map));

becomes:

SupportMapFragment m = ((SupportMapFragment) getChildFragmentManager()
        .findFragmentById(R.id.safety_map));
Deputize answered 27/10, 2014 at 23:37 Comment(11)
Is there really such a difference between Fragment.getActivity().getSupportFragmentManager() and Fragment.getFragmentManager() ? From the documentation it seems they should act the same at first glance.Polacre
The Activity's fragment manager manages the Activity's direct fragments. Each fragment has its own FragmentManager that manages that fragment's child fragments. So, your Activity contains your map-hosting Fragment in the manager. That map-hosting Fragment contains the SupportMapFragment in its manager.Deputize
Shouldn't you call then Fragment.getChildFragmentManager() ? Maybe I'm mistaken though.Polacre
The confusing thing is, from FragmentActivity you need to use getSupportFragmentManager(). However, from a Fragment, getFragmentManager() will call through to getActivity().getSupportFragmentManager(). To get the Fragment's manager, you should call getChildFragmentManager() from a Fragment.Deputize
Thanks for the comments. We have a winner! I put a breakpoint and tried all three... getFragmentManager(), getActivity().getSupportFragmentManager(), and getChildFragmentManager(). The only one that worked was getChildFragmentManager(). I updated to targetSdkVersion 21 maybe that is why what I had prev no longer works. thx :)Nikolos
@user1732917 Yes the problem occurs when updating to SDK 21. Just had the same issue. Thanks man!Vosges
Wow, thanks. I needed this only when I updated to material design (compileSdkVersion 21 in build.gradle), before that it wasn't needed.Heighten
Its working for me..under Fragment and also I did used ViewPager.Boarer
What a brilliant explanation. I wondered why this doesn't work for Fragments but Activity! I too tried with Breakpoints and concluded that getChildFragmentManager() is the correct implementation since it addresses the Support Fragment inside Fragment. saved my day!Feather
This is brilliant! Never thought something like this existed! Thanks!Orthogenetic
Or if you're using kotlin, just use childFragmentManager instead of getChildFragmentManager()Monogenic
A
18

Yes. It's not work for targetSdkVersion 21, if your Map fragment is inner part of Fragment (due to some issues, that mentioned this and this).

As temporary resolving can advice such trick:

public class MyFragment extends Fragment {

    private SupportMapFragment fragment;
    private GoogleMap map;

    @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();
        fragment = (SupportMapFragment) fm.findFragmentById(R.id.map_container);
        if (fragment == null) {
            fragment = SupportMapFragment.newInstance();
            fm.beginTransaction().replace(R.id.map_container, fragment).commit();
        }
    }
}
Alarise answered 11/2, 2015 at 10:41 Comment(4)
Why is this a temporary solution?Inverse
@BartaTamás It was a bug and I though that it will be fixed soon. But it still not fixed. (See references above)Alarise
Thanks, I see. I thought this is a design decision by the Google guys.Inverse
@TamásBarta no my friend, this is a BUG in their design decision !Whereunto
F
4

The following code worked for me. I was using Google Map in a Fragment:

 SupportMapFragment m = ((SupportMapFragment) getChildFragmentManager() .findFragmentById(R.id.safety_map));
Fragrance answered 19/7, 2016 at 22:6 Comment(0)
C
4

All the answers are correct in their respective manner. It may happen that you follow someones's java code which is working for them but not work for you because you had different implementation in your xml code than them.

So let me give you my opinion how I managed to load map in both Activity as well as Fragment

Activity:

 <fragment
    android:name="com.google.android.gms.maps.MapFragment"
    android:id="@+id/map"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

Java class:

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

In Fragment:

<fragment
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

Java class:

 SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map);
Century answered 9/2, 2017 at 7:7 Comment(1)
getChildFragmentManager doesn't work with SupportMapFragment. It tells me "can't resolve method".Blower

© 2022 - 2024 — McMap. All rights reserved.