2

I have a ViewPager that pages through ListFragments. Each page is a specific date and the list in each page contains items in mulitple categories.

The user can at any moment toggle the displayed categories through a dialog. This is not a problem for pages (and their fragments) instantiated after the change in categories list since they are instantiated with the new settings (passed to the FragmentStatePagerAdapter the moment they change).

But my problem is with all pages that have already been instantiated up to when the user changes the categories list. These pages (or rather, their fragments) need to immediately refresh. To accomplish this I need to be able to call a method (changeData()) to pass the new categories settings to each ListFragment which then calls notifyDataSetChanged() so they will refresh their view.

How can I perform this call on already-instantiated fragments in the FragmentStatePagerAdapter?

Here is my code for the FragmentStatePagerAdapter and the ListFragments used to populate the pages:

public static class ListingPagerAdapter extends FragmentStatePagerAdapter {

    private Date mStartingDate;
    private String mListingCat;
    private Calendar cal;

    public ListingPagerAdapter(FragmentManager fm, Date startDate, String listingCat) {
        super(fm);
        mStartingDate = startDate;
        mListingCat = listingCat;
        cal = Calendar.getInstance();
    }

    public void setListingCategories(String categories) {
        mListingCat = categories;
        //notifyDataSetChanged();
    }

    @Override
    public Fragment getItem(int i) {
        cal.setTime(mStartingDate);
        cal.add(Calendar.DAY_OF_YEAR,i);
        Bundle fragmentArgs = new Bundle();
        fragmentArgs.putString(Utils.DIRECTORY_CAT_STORE_KEY, mListingCat);
        fragmentArgs.putLong(Utils.FILTER_DATE_STORAGE_KEY, cal.getTimeInMillis());
        ListingFragment listingFragment = ListingFragment.newInstance(fragmentArgs);
        return listingFragment;
    }

    @Override
    public int getItemPosition(Object object) {
        if (object instanceof ListingFragment) {
            ((ListingFragment) object).changeData(mListingCat, 0);
        }
        return super.getItemPosition(object);
    }

    @Override
    public int getCount() {
        return Integer.MAX_VALUE;
    }
}

You will notice the seListingCategories() method above which I use to set the category string on the adapter and thus every newly instantiated Fragment has the correct categories to display. In the same method you will notice a line commented out that calls notifyDataSetChanged() on the Adapter.

That call causes the adapter to call getItemPosition() for every Fragment in memory (current page and all others not yet destroyed) and I take that chance to call changeData() on them this way. And the views are successfully updated.

However, it seems that fragments already destroyed (with saved state) just get restored to their saved state which doesn't have the updated category list. Not to mention that this seems overkill. Why destroy and recreate every fragment when I could just update the existing objects?

Anyway, below is the ListFragment class used in the FragmentStatePageAdapter:

public static class ListingFragment extends ListFragment {

    private Map<String,String> filters;
    private JSONArray mListingData;

    public static ListingFragment newInstance(Bundle args) {
        ListingFragment lf = new ListingFragment();
        lf.setArguments(args);
        return lf;
    }

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

        if (filters == null)
            filters = new HashMap<String, String>();

        if (savedInstanceState != null) {
            filters.put(Utils.DIRECTORY_CAT_STORE_KEY, savedInstanceState.getString(Utils.DIRECTORY_CAT_STORE_KEY));
            filters.put(Utils.FILTER_DATE_STORAGE_KEY, ""+savedInstanceState.getLong(Utils.FILTER_DATE_STORAGE_KEY));
        }
        else {
            filters.put(Utils.DIRECTORY_CAT_STORE_KEY, getArguments().getString(Utils.DIRECTORY_CAT_STORE_KEY));
            filters.put(Utils.FILTER_DATE_STORAGE_KEY, ""+getArguments().getLong(Utils.FILTER_DATE_STORAGE_KEY));
        }

        mListingData = Utils.getDataByTypeAndFilters(getResources().getString(R.string.nav_promotions), filters, getActivity().getResources());
        setListAdapter(new PromotionListingAdapter(getActivity(), mListingData));

    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putString(Utils.DIRECTORY_CAT_STORE_KEY, filters.get(Utils.DIRECTORY_CAT_STORE_KEY));
        outState.putLong(Utils.FILTER_DATE_STORAGE_KEY, Long.parseLong(filters.get(Utils.FILTER_DATE_STORAGE_KEY)));
        super.onSaveInstanceState(outState);
    }

    @Override
    public void onListItemClick(ListView l, View view, int position, long id) {
        Intent newDetailIntent = new Intent(getActivity(), PromotionDetails.class);
        newDetailIntent.putExtra(Utils.LISTING_OBJECT_STORE_KEY, ((JSONObject) l.getAdapter().getItem(position)).toString());
        startActivity(newDetailIntent);
    }

    public void changeData(String category, long date) {
        if (category != null)
            filters.put(Utils.DIRECTORY_CAT_STORE_KEY, category);
        if (date > 0)
            filters.put(Utils.FILTER_DATE_STORAGE_KEY, ""+date);
        mListingData = Utils.getDataByTypeAndFilters(getResources().getString(R.string.nav_promotions), filters, getActivity().getResources());
        PromotionListingAdapter promotionsAdapter = ((PromotionListingAdapter) getListAdapter());
        promotionsAdapter.setData(mListingData);
        promotionsAdapter.notifyDataSetChanged();
    }
}

Thanks in advance for any help!

RobertoCuba
  • 881
  • 9
  • 25

0 Answers0