2

I working on my first app and got problems with the "back" function.

When i open the app an click in the menu to another fragment (2,3 or 4) and i push the back button the app crashes. When i start the app and click 2 > 3 > 4 (in this order) in the menu and push the back button i go back to 3 > 2 > crash. The app crashes when i go back to the mainFragment which contains a google map.

I think my problem has something to do with the googlemap in this fragment (the fragment to navigate back to) because when i set 2 enters before the error line in the xml of that view and run again, the error line number is +2. and when i comment out this fragment the back button works fine.

By navigate to an new fragment i call:

fragmentTransaction.replace(R.id.fr_content_container, new NewsFragment()).addToBackStack(null).commit();

The error i get is

04-01 14:26:39.679 19054-19054/aaeu.app E/AndroidRuntime: FATAL EXCEPTION: main
                                                          Process: aaeu.app, PID: 19054
                                                          android.view.InflateException: Binary XML file line #7: Binary XML file line #7: Error inflating class fragment
                                                              at android.view.LayoutInflater.inflate(LayoutInflater.java:539)
                                                              at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
                                                              at aaeu.app.presentationlayer.tab_AlertMapsOverview.onCreateView(mapsFragment.java:52)
                                                          .....................

The XML of the mapsFragment is:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >

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

The code of the map fragment is:

    private SupportMapFragment mMapFragment;
    private AlertManager mAlertManager;
    private GoogleMap mGoogleMap;
    HashMap<Marker, Alert> mMarkerMap;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAlertManager = new AlertManager(getContext());
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.overview_maps_alert_tab, container, false);
        ButterKnife.bind(this, view);

        loadMap();

        return view;
    }

    private void loadMap() {
        mMapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.mapwhere);
        if (mMapFragment == null) {
            FragmentManager fragmentManager = getFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            mMapFragment = SupportMapFragment.newInstance();
            fragmentTransaction.replace(R.id.mapwhere, mMapFragment).commit();
        }

        if (mMapFragment != null) {
            mMapFragment.getMapAsync(new OnMapReadyCallback() {
                @Override
                public void onMapReady(GoogleMap googleMap) {
                    if (googleMap != null) {
                        googleMap.getUiSettings().setAllGesturesEnabled(true);

                        LatLng marker_latlng = new LatLng(55.042684, 14.125549);

                        CameraPosition cameraPosition = new CameraPosition.Builder().target(marker_latlng).zoom(3.0f).build();
                        CameraUpdate cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition);
                        googleMap.moveCamera(cameraUpdate);

                        setGoogleMap(googleMap);
                    }
                }
            });
        }
    }

    private void setGoogleMap(GoogleMap googleMap) {
        this.mGoogleMap = googleMap;
    }


    // This method is called by the asynctask who downloads the alerts
    @Override
    public void UpdateAlerts(List<Alert> alerts) {

        mMarkerMap = new HashMap<Marker, Alert>();
        try {
        for (Alert alert : alerts) {
            MarkerOptions marker = new MarkerOptions();
            marker.position(alert.Location.get(0));
            marker.title(alert.GetFullName());

            Marker m = mGoogleMap.addMarker(marker);
            mMarkerMap.put(m, alert);
        }


            mGoogleMap.setOnMarkerClickListener(
                    new GoogleMap.OnMarkerClickListener() {
                        @Override
                        public boolean onMarkerClick(Marker marker) {
                            startDetailView(marker);
                            return false;
                        }
                    }
            );
        }
        catch (NullPointerException e)
        {
            Log.i("tab_AlertMapsOverview","No missings to create markers for or set clicklisteners on. Are there missings in the configured Areas?");
        }
    }

Near this problem i have a little question too. When i have 3 fragments, 1, 2 and 3. When i (for example) start in activity 1 and navigate to 2 > 3 > 2 > 3 i need to push 4 times back to come back in 1. Is it posible to use a kind of "tree" system for back navigation. so i allways go up 1 level? Maybe this clears up what i mean.

this I think also the current situation is far from optimal becouse the fragments are still active in RAM? or are i'am wrong?

CodeNinja
  • 836
  • 1
  • 15
  • 38

2 Answers2

2

I too had the same Issue. After wasting a lot of time searching for the solution, what i finally did was, I removed fragment tag from xml. Put a FrameLayout there and whenever I want to add that fragment, I would add it with fragment transaction. That worked out for me.

The cause for the issue is, whenever onCreateView() for that fragment is called, the xml file will be inflated which will inflate the fragment. This will lead to multiple fragments with the same id which causes this exception.

Ankit Aggarwal
  • 5,317
  • 2
  • 30
  • 53
  • I dont understand this 100%. Which tag you exacly deleted?, the whole `Frament` tag? or only the ` android:name="com.google.android.gms.maps.SupportMapFragment"` part? And what do you mean with "put a there"? I understand that the `onCreate` inflates the XML but why should my xml inflate the fragment again? (or does it inflate another fragment?) – CodeNinja Apr 01 '16 at 13:25
  • 1
    the tag you should delete and replace it with a and use normal fragment transaction to add the maps fragment, the same way you are doing for NewsFragment. Actually if you come back to the fragment again, its onCreateView() will be called again which will inflate the fragment again and both fragments will have the same ids – Ankit Aggarwal Apr 01 '16 at 13:30
  • The back button works great BUT when i go back to an maps activity sometimes the maps is show but mostly not. When i navigate to the maps activity over the menu the map is allways show. Do you also have a solution for this problem ? – CodeNinja Apr 05 '16 at 09:23
  • in which method did you write the code for fragmenttransaction ? onCreate() or orActivityStarted() or onStart() or somewhere else? – Ankit Aggarwal Apr 05 '16 at 09:27
  • I "create" the maps fragment object in the `onCreate()` and do the transaction in the `OnCreateView()` (i use fragements instead of activity's). When the map is not loaded i see the "empty" `FrameLayout` which is defined in the XML. – CodeNinja Apr 05 '16 at 09:39
  • 1
    If you are adding maps fragment from another fragment, than use getChildFragmentManager() instead of getFragmentManager() – Ankit Aggarwal Apr 05 '16 at 09:43
  • I need to try this 100 times to be sure that it 100% works but it looks like it works now. I'am pretty new with Android and for these things you search hours and its so easy to solve! Thanks for your GREAT easy to understand help! – CodeNinja Apr 05 '16 at 09:54
  • If in any case this also fails, put the fragmenttransaction code inside the onStart() method. – Ankit Aggarwal Apr 05 '16 at 10:01
  • I think this is the perfect solution. Instead of including the fragment itself we can include it programmatically. – Murtaza Khursheed Hussain Feb 28 '17 at 06:24
0

Replace your onBackPressed with this...

 @Override
    public void onBackPressed() {
        // if there is a fragment and the back stack of this fragment is not empty,
        // then emulate 'onBackPressed' behaviour, because in default, it is not working
        FragmentManager fm = getSupportFragmentManager();
        for (Fragment frag : fm.getFragments()) {
            if (frag.isVisible()) {
                FragmentManager childFm = frag.getChildFragmentManager();
                if (childFm.getBackStackEntryCount() > 0) {
                    childFm.popBackStack();
                    return;
                }
            }
        }
        super.onBackPressed();
    }