SupportMapFragment null on SECOND load

448 views Asked by At

There is long time I'm trying to solve this issue. I've read so much questions about similiar issues on stackoverflow and other sources that I'm unable to list all of them.

My problem is different from the others I've read since the first time I try load the fragment with the map all works fine... Is on the second time I try to access the fragment with the map without restarting the app that it crashes with a null pointer on:

googleMap = map.getMap();

because map is null:

 map = (SupportMapFragment) myContext.getSupportFragmentManager().
           findFragmentById(R.id.map);

The key differences are then:

  • The first time it works fine
  • The second time findFragmentById returns null, but no error

I can't debug it because AVD emulator has no Google Play services installed.

MainActivity has a NavigationDrawer, and depending on the option selected, a Fragment or another is selected. Here some of the code related to this issue:

fragment_map.xml:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

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

</RelativeLayout>

MyFragment.java:

...
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
...
public class MyFragment extends Fragment implements
        GooglePlayServicesClient.ConnectionCallbacks,
        GooglePlayServicesClient.OnConnectionFailedListener {

    private GoogleMap googleMap;
    private View fragmentView;
    private static WorldFragment fragment;
    private FragmentActivity myContext;
    ...

    public static MyFragment getInstance() {
        if (fragment == null) {
            fragment = new MyFragment();
        }
        return fragment;
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        myContext = (FragmentActivity) activity;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        try {
            GlobalState gs = (GlobalState) getActivity().getApplication(); 
            // recover View from previous use
            fragmentView = gs.getWorldFragmentView(); 
            if (fragmentView == null) {
                fragmentView = inflater.inflate(R.layout.fragment_map, 
                                    container, false);
                // save View for next use
                gs.setFragmentView(fragmentView); 
            } else {
                ViewGroup parent = (ViewGroup) fragmentView.getParent();
                parent.removeView(fragmentView);
            }
        } catch (InflateException e) {
            // map is already there, just return view as it is
        }
        return fragmentView;
    }

    ...

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        // Set up the map fragment
        SupportMapFragment map = (SupportMapFragment) myContext.
             getSupportFragmentManager().findFragmentById(R.id.map);
        /*  // If I active this code, no crash, but fragment remains 
            // in gray background without map.
            // At least, if the app crashes, it restarts and the map 
            // gets loaded the first time
        if (map == null) {
            Toast.makeText(getActivity(), getString(R.string.maps_not_supported), 
                   Toast.LENGTH_LONG).show();
            return;
        } */
        googleMap = map.getMap();
        if (googleMap != null) {
            // Enable the current location "blue dot"
            googleMap.setMyLocationEnabled(true);
            ...
        } else {
            Toast.makeText(getActivity(), getString(R.string.maps_not_supported), 
                   Toast.LENGTH_LONG).show();
        }
    }

    ...
}

MainActivity.java:

public class MainActivity extends FragmentActivity implements
    NavigationDrawerFragment.NavigationDrawerCallbacks {

    @Override
    public void onNavigationDrawerItemSelected(int position) {
        Fragment contentFragment;
        switch (selectedOption) {
            case MAP:
                contentFragment = MyFragment.getInstance();
                break;
            case XXX:
                ...
                break;
            default:
                contentFragment = new OtherFragment(); 
        }
        // update the main content by replacing fragments
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction()
                .replace(R.id.container, contentFragment)
                .commit();
    }
}

Stacktrace:

java.lang.NullPointerException
   at xxx.xxxxx.xxx.fragments.MyFragment.onActivityCreated(MyFragment.java:193)
   at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:1508)
   at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:958)
   at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1115)
   at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
   at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1478)
   at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:446)
   at android.os.Handler.handleCallback(Handler.java:725)
   at android.os.Handler.dispatchMessage(Handler.java:92)
   at android.os.Looper.loop(Looper.java:153)
   at android.app.ActivityThread.main(ActivityThread.java:5297)
   at java.lang.reflect.Method.invokeNative(Method.java)
   at java.lang.reflect.Method.invoke(Method.java:511)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
   at dalvik.system.NativeStart.main(NativeStart.java)

Please, let me know if you need some more information.

Thank you very much for your time and attention.

30/12/2014: source code of MainActivity's onCreate() method

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    GlobalState applicationContext = (GlobalState) getApplicationContext();
    applicationContext.updateLocale();

    NavigationDrawerFragment.setItems(applicationContext.getMenuItems());
    setContentView(R.layout.activity_main);

    mNavigationDrawerFragment = (NavigationDrawerFragment)
            getFragmentManager().findFragmentById(R.id.navigation_drawer);
    mTitle = getTitle();

    // Set up the drawer.
    mNavigationDrawerFragment.setUp(
            R.id.navigation_drawer,
            (DrawerLayout) findViewById(R.id.drawer_layout));

    // Treating incoming notifications
    Intent intent = getIntent();
    String action = intent.getAction();
    if (action != null && !action.isEmpty()) {
        ItemType itemType = ItemType.valueOf(action);
        String title = applicationContext.getMenuItemByType(itemType).getTitle();
        String itemId = null;
        try {
            JSONObject json = new JSONObject(intent.getExtras().getString("com.parse.Data"));
            itemId = json.getString(EXTRA_ITEM_ID);
        } catch (JSONException e) {
            Crashlytics.logException(e);
        }
        launchFragment(itemType, null, title, itemId);
    }
}
1

There are 1 answers

3
ztan On

You have to remove the fragment in the onDestroyView() method of your MyFragment class.

Sample code to remove:

@Override
   public void onDestroyView() {
       SupportMapFragment f = (SupportMapFragment)myContext.getSupportFragmentManager().findFragmentById(R.id.map);

       if (f != null) {
           try {
               myContext.getSupportFragmentManager().beginTransaction().remove(f).commit();
           }
           catch (Exception e) {
               e.printStackTrace();
           }
       }
       super.onDestroyView();
   }