0

I am having a problem managing a changing list of item using the FragmentStatePagerAdapter. Please check source here.

The problem is that when the underlying list changes, and I call notifyDataSetChanged, the adapter does not rebuild it's internal list of fragments. Referring to the code in instantiateItem:

@Override
public Object instantiateItem(ViewGroup container, int position) {
    // If we already have this item instantiated, there is nothing
    // to do.  This can happen when we are restoring the entire pager
    // from its saved state, where the fragment manager has already
    // taken care of restoring the fragments we previously had instantiated.
    if (mFragments.size() > position) {
        Fragment f = mFragments.get(position);
        if (f != null) {
            return f;
        }
    }

I believe the code in this comment is wrong! If I delete the item at position 0 in the list, and I call notifyDataSetChanged, then the fragment at position 0 should be deleted. However the adapter has never updated the position of fragments in its own private list. Therefore it still shows the old, deleted, data.

I found this answer but it is a hack that relies on getItemPosition being called and then forcing the fragment to update it's views.

How is it possible to manage fragments in a changing list?

Community
  • 1
  • 1
Greg Ennis
  • 14,917
  • 2
  • 69
  • 74

1 Answers1

1

Per the ViewPager.dataSetChanged() source, it uses PagerAdapter.getItemPosition() to determine the new position of a item after a data change. By default, getItemPosition() always returns POSITION_UNCHANGED, meaning it never destroys and recreates items it has already created.

Override getItemPosition() to return the correct value if you want to update Fragments that already exist in response to a notifyDataSetChanged() call. For example, always returning POSITION_NONE will always destroy every Fragment and recreate them from scratch (which, in most cases, is more work than needs to be done if items are just reordering).

ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
  • Even always returning POSITION_NONE does not fix the issue I'm describing, since the internal list of fragments mFragments still holds the old fragment in the old position. – Greg Ennis Dec 02 '14 at 00:04
  • No, if you use `POSITION_NONE` then `destroyItem` is called and `mFragments.get(position)` returns `null` and we instantiate a new instance. – ianhanniballake Dec 02 '14 at 00:06
  • Ian, I have constructed a simple example which reproduces the problem. I was hoping you could take a look. Notice how you can swipe through the 4 pages. However, then go to page 1, press Delete on action bar, then swipe to the right - page is blank. Then swipe to the end and back to the beginning - app crashes. Perhaps I am doing something wrong, but I cant see what is would be. https://dl.dropboxusercontent.com/u/31143706/testapp.zip – Greg Ennis Dec 02 '14 at 02:02
  • I cant get my simple example to work. I am sure this is a bug. I will submit the bug report. – Greg Ennis Dec 05 '14 at 15:08
  • I took a look at the app you sent: always returning `POSITION_NONE` at least got it working of sorts, but there is definitely something odd going on when using the correct implementation of `getItemPosition` – ianhanniballake Dec 05 '14 at 15:11