Remove all fragments from ViewPager populated by FragmentStatePagerAdapter

ngwane picture ngwane · May 15, 2013 · Viewed 23.3k times · Source

I have a ViewPager that I am populating with fragments(representing objects from arrayListOfObjects) using FragmentStatePagerAdapter. All works well:

            mMyFragmentPagerAdapter = new fragmentAdapter(getSupportFragmentManager(),orientation
            ,rePopulatedfireInfoList);
        mPager = (ViewPager)findViewById(R.id.fireInfoFragment_container);
        initButton();
        setTab();
        mPager.setAdapter(mMyFragmentPagerAdapter); 

The fragment adapter extends FragmentStatePagerAdapter.

From the primary activity I launch a dialog themed activity; where the user may add a new favourite location creating a new object which alters the arraylist of objects passed by the primary activity. This is the code for starting dialog activity; all works fine:

        Intent locationIntent = new Intent(afisController.this, locationActivity.class);
    locationIntent.putExtra("firesList", new fireInfoListWrapper(arrayListOfObjects));
    startActivityForResult(locationIntent,1);

The floating activity adds objects into arrayListOfObjects.

On the primary activity's onActivityResult I compare the arraListOfObjects I'm receiving with the one I sent; if different I want to completely remove the contents of the viewPager and recreate it with the new arrayListOfObjects. This is the onActivityResults:

     protected void onActivityResult(int requestCode, int resultCode,
            Intent data) {
 Toast.makeText(this, "Activity Results fired..." , 1500 ).show();
            if ((resultCode == 0) && (data != null)) { 
                Log.i("onActvityResult", "Inside resultCode check");   
                Bundle b = data.getExtras();
                if(b != null){
                    Log.i("onActvityResult", "not null");
                    returnedFireInfoList = (ArrayList<fireInfo>) data.getSerializableExtra("firesListResult"); 
                    Log.i("onActvityResult", "results Size: "+returnedFireInfoList.size());
                    if(returnedFireInfoList.size()>0){
                        Log.i("onActvityResult", "locationName: "+returnedFireInfoList.get(0).getLocationName());
                        //compare returnedFireInfoList and rePopulatedfireInfoList, if different; 
                        //add difference to rePopulatedfireInfoList and write back to file.
                        updateFireInfos(returnedFireInfoList, rePopulatedfireInfoList);
        if(returnedFireInfoList.size()!=rePopulatedfireInfoList.size()){
mMyFragmentPagerAdapter1 = new fragmentAdapter(getSupportFragmentManager(),orientation
                    ,returnedFireInfoList);
            mPager = (ViewPager)findViewById(R.id.fireInfoFragment_container); 
            Log.i("updateFireInfos", "fragmentsCount is"+mPager.getCurrentItem());
            fireInfoFragment fragment = 
                      (fireInfoFragment) getSupportFragmentManager().findFragmentById(R.id.fireInfoFragment_container);
//This is where the problem is, I don't want to remember what was already on the viewPager //called mPager before.
           //   mPager.removeAllViews();
            //mPager.setAdapter(null);
            mMyFragmentPagerAdapter1.notifyDataSetChanged();            
            mPager.setAdapter(mMyFragmentPagerAdapter1);               mMyFragmentPagerAdapter1.notifyDataSetChanged();                     
                    }                   
                }
            }        

This is the fragmentStateAdapter code:

public class fragmentAdapter extends FragmentStatePagerAdapter {

private FragmentManager fragmentManager;
 private FragmentTransaction mCurTransaction = null;
 private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
 private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
 private Fragment mCurrentPrimaryItem = null;



public void restoreState(Parcelable state, ClassLoader loader) {
    //Need to only delete info from marked fragments (theoned that are stored on orientationchange
    //Currently redoing the entire call; resulting in delay due to server call
    //if(isLastOrientationPortrait != isPortrait){
    if(state != null){
        Bundle bundle1 = (Bundle) state;
        bundle1.setClassLoader(loader);
        Iterable<String> keys = bundle1.keySet();
        Log.i("restoreState", "containsKey FragmentStatePagerAdapter: "+keys);
        //android.support.v4.app.FragmentManager fragmentManager= fragmentAdapter.this.fragmentManager;
        android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); 
        //if (fragmentTransaction == null) {
        //  Log.i("restoreState", "fragmentTransactionTest");

            fragmentTransaction = fragmentManager.beginTransaction();
       // }
        for (String key : keys) {
            if (key.startsWith("f")) {
                Fragment f = fragmentManager.getFragment(bundle1,
                        key);
                fragmentTransaction.remove(f);
                fragmentTransaction.commit();
            }
            }
        }
    //}       
    }


@Override
public int getItemPosition(Object object) {
    // TODO Auto-generated method stub
    //return super.getItemPosition(object);
    return fragmentAdapter.POSITION_NONE;
}


public fragmentAdapter(android.support.v4.app.FragmentManager fragmentManager,String orientation,
         ArrayList<fireInfo> fireInfoList) {
     super(fragmentManager);
     this.orientation = orientation;
     this.fireInfoList = fireInfoList;
     this.numItems = fireInfoList.size();
     this.fragmentManager=fragmentManager;
 }
 ArrayList<fireInfo> fireInfoList;
 String orientation;
 int numItems;


@Override
 public int getCount() {
     Log.i("numItems", "is: "+fireInfoList.size());
     return numItems;
 }

@Override
public Fragment getItem(int arg0) {
    Log.i("fragmentAdapterIndex", "is: "+arg0);
    return fireInfoFragment.newInstance(orientation, fireInfoList.get(arg0));
}    

}

Problem: But the new ArrayListOfObjects is added alongside the old one before I fired the startActivityFor results.

How do I force the viewPager to forget it old content? basically reset the viewPager adapter with this newArrayListofObjects using my fragmentStateAdapter?

Answer

Alex Semeniuk picture Alex Semeniuk · Nov 19, 2013

I guess the problem is in the fact that old fragments still reside in FragmentManager you use for your adapter. If this is the case all you have to do is remove all old fragments from the fragment manager.

So basically just execute the following code in the constructor of your adapter:

public fragmentAdapter(FragmentManager fragmentManager, String orientation, ArrayList<fireInfo> list) {
    super(fragmentManager);
    if (fragmentManager.getFragments() != null) {
        fragmentManager.getFragments().clear();
    }
    //... your other code here
}

This line of code is unnecessary:

mMyFragmentPagerAdapter1.notifyDataSetChanged();     

EDIT: It may be more correct to remove your fragments using FragmentTransaction:

    List<Fragment> fragments = fragmentManager.getFragments();
    if (fragments != null) {
        FragmentTransaction ft = fragmentManager.beginTransaction();
        for (Fragment f : fragments) {
            //You can perform additional check to remove some (not all) fragments:
            if (f instanceof AddedByCurrentPagerAdapterFragment) { 
                ft.remove(f);
            }
        }
        ft.commitAllowingStateLoss();
    }

This will take some time for FragmentTransaction to be (asynchronously) performed.