Search code examples
javaandroidandroid-listfragmentsupportmapfragment

ActionBarActivity problems returnin to ListFragment for api10f


I have a android.support.v7.app.ActionBarActivity that has a FrameLayout holding a SupportMapFragment and android.support.v4.app.ListFragment.

I instantiate both fragments in the OnCreate of ActionBarActivity

        if(mFM.findFragmentByTag("ListFragment")==null){
            mPlaceListFragment = new PlaceListFragment_1();
            mFM.beginTransaction().add(R.id.listfragment_container, mPlaceListFragment,"ListFragment").commit();
        }else{
            mPlaceListFragment = (PlaceListFragment_1)mFM.findFragmentByTag("ListFragment");
        }

        if(mFM.findFragmentByTag("MapFragment")==null){
            mMapFragment = new map_fragment(); //always create map fragment
            mFM.beginTransaction().add(R.id.mapfragment_container, mMapFragment,"MapFragment").commit();
        }else{
            mMapFragment = (map_fragment) mFM.findFragmentByTag("MapFragment");
        }

And in order to avoid recreating each fragment when it’s selected I hide/show them depending on which one is selected.

@Override
public boolean onNavigationItemSelected(int i, long l) { //OnFragmentInteractionListener

    FragmentTransaction ft = mFM.beginTransaction();

    if(i==0){
        //map
        if (mPlaceListFragment.isVisible())ft.hide(mPlaceListFragment);
        if (mMapFragment.isHidden())ft.show(mMapFragment);
    }else{
        //list
        if (mPlaceListFragment.isHidden())ft.show(mPlaceListFragment);
        if (mMapFragment.isVisible())ft.hide(mMapFragment);
    }

    ft.commit();

    return true; //True if the event was handled, false otherwise.
}

This all works fine. I can select each Fragment using the dropdown in ActionBar and manipulate UI etc. Orientation change also works ok. The problem occurs when the ListFragment is visible and the app opens a new Activity and the back key is pressed to return to the original Activity.

OR

the ListFragment is visible and the HOME button is pressed and an attempt is made to reopen the app from the task bar.

The problem doesn’t occur with the map fragment just the ListFragment. Also the app works for in GenyMotion emulators for API17+

The app returns to the ListFragment ok but the UI controls (actionbar controls and activity dropdowns etc.) are not responsive and the screen fades and becomes unresponsive.

There is no LogCat error.

It appears to be a problem with API10 and occurs when returning to the ListFragment??

Overrides on ActionBarActivity

@Override
protected void onResume() {
    //activity - after onstart
    super.onResume();
    if(mAdView!=null) mAdView.resume();

    FragmentTransaction ft = mFM.beginTransaction();

    if(getSupportActionBar().getSelectedNavigationIndex()==0){
        //show map
        ft.show(mMapFragment);
        ft.hide(mPlaceListFragment);
    }else{
        //show ListFragment
        ft.show(mPlaceListFragment);
        ft.hide(mMapFragment);
    }
    ft.commit();
}

@Override
protected void onPause() {
    //activity
    if(mAdView!=null)  mAdView.pause();
    super.onPause();
}

@Override
protected void onStop() {
    super.onStop();
    // If the client is connected
    if (mLocationClient!=null && mLocationClient.isConnected()) {
        /*
         * Remove location updates for a listener.
         * The current Activity is the listener, so
         * the argument is "this".
         */
        mLocationClient.removeLocationUpdates(this);
        mLocationClient.disconnect();
    }


    EasyTracker.getInstance(this).activityStop(this);//put as last statement
}

@Override
protected void onDestroy() {
    //activity
    if(mAdView!=null) mAdView.destroy();
    super.onDestroy();
    //clean the file cache when root activity exit
    //the resulting total cache size will be less than 3M
    if(isTaskRoot()){
        AQUtility.cleanCacheAsync(this);
    }

    if (mLocationClient !=null && !mLocationClient.isConnected()) mLocationClient.disconnect();

}



        ********************************************************************
        //All handlers are set in Oncreate of main ActionBarActivity e.g.
        //ActionBar Spinner
       ********************************************************************

        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
            mSpinnerAdapter = ArrayAdapter.createFromResource(actionBar.getThemedContext(), R.array.action_list, android.R.layout.simple_spinner_dropdown_item);
        }else{
            mSpinnerAdapter = ArrayAdapter.createFromResource(actionBar.getThemedContext(), R.array.action_list, android.R.layout.simple_spinner_dropdown_item);
            //mSpinnerAdapter = ArrayAdapter.createFromResource(actionBar.getThemedContext(), R.array.action_list, R.layout.navigation_spinner_item);
        }
        actionBar.setListNavigationCallbacks(mSpinnerAdapter, this);

         ********************************************************************
        //other spinners and views belonging to main activity
         ********************************************************************
        mSprSavedPlaces = (Spinner) findViewById(R.id.spr_saved_places);
        mSprSavedPlaces.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
               //stuff
             }

         //Also the Map and List fragments are repopuplated from via the main
         //ActionBarActivity’s onSaveInstanceState and onRestoreInstanceState
         //this seems to work ok. 

this question posted a while back raises same issue as I'm experiencing: Back button very slow


Solution

  • At last I found a solution to this problem. In summary the problem occurred when switching between a SupportMapFragment and ListFragment. Hide/show methods of the FragmentTransaction class were used to toggle between both fragments stored in a single FrameLayout. However if the SupportMapFragment was in its hidden state and control was passed to a new activity and back again there would be a big delay coming back and the UI would be unresponsive.

    There was no problem if the SupportMapFragment was visible. This occurred for an Android 2.3.3 (Samsung Galaxy) phone only and there wasn’t a problem with emulators running HoneyComb +

    See below for solution description and code:

    /**
     * Show selected fragment and hide other.
     *
     * Could not use ft.hide/show for SupportMapFragment because this caused
     * big delays coming back to main screen from other activities when the SupportMapFragment was
     * in its hidden state. It also caused the UI to become unresponsive.
     * 
     * I solved this by hiding/showing the SupportMapFragment by removing/adding the fragment for
     * its container view. Working on 2.3.3 and Honeycomb --> KitKat emulators
     */
    private void showFragment(Fragment fragmentIn) {
        if (fragmentIn == null || mFragmentVisible == fragmentIn) {
            return;
        }
    
        View mapView=mMapFragment.getView();
    
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    
        if(fragmentIn instanceof map_fragment){
            //show map
            if (mapView.getParent()!=mFragmentContainer) { //mFragmentContainer is FrameLayout
                mFragmentContainer.addView(mapView);
            }
            ft.hide(mPlaceListFragment);
        }else{
            //show list
            mFragmentContainer.removeView(mapView);
            ft.show(mPlaceListFragment);
        }
    
        ft.commit();
    
        mFragmentVisible = fragmentIn;
    }