2

I want to prepend a new View as first page of my ViewPager. My adapter looks like this:

public class PagerAdapter extends FragmentPagerAdapter {

    private final List<Fragment> fragments;

    public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
        super(fm);
        this.fragments = fragments;
    }

    @Override
    public Fragment getItem(int index) {
        return fragments.get(index);
    }

    @Override
    public int getCount() {
        return fragments.size();
    }

    public void add(int i, ImageFileObject imageFile) {
        ImageViewFragment f = new ImageViewFragment();
        f.setImage(imageFile);
        fragments.add(0, f);
        notifyDataSetChanged();
    }

    public void add(ImageFileObject imageFile) {
        ImageViewFragment f = new ImageViewFragment();
        f.setImage(imageFile);
        fragments.add(f);
        notifyDataSetChanged();
    }

}

But when calling add(0, aImageFile) the item is not prepended to the fragment list. (It's not even appended).

Any ideas?

Basic Coder
  • 9,053
  • 5
  • 39
  • 71

2 Answers2

2

Update: The problem that you described in comment is real, I missed it in first testing. After analyzing the source code of FragmentPagerAdapter I realized that all we need to do is to Override getItemId() in a way that it won't return same id for different fragment items. E.g. current default implementation would just return position as an id for fragment which won't work for this case:

 public long getItemId(int position) {
    return position;
}

I am updating this answer, please have a look. As before I have tested this code and the problem you described is not happening now.


Only thing you need is not to keep reference of fragments by yourself in List, This is done for you by FragmentPagerAdapter. And as far as I know its not a good practise either. And also even if you return POSITION_NONE from getItemPosition() as suggested by other answer(s), you will end up with Exception

Caused by: java.lang.IllegalStateException: Can't change tag of fragment.

This is because you are trying to reposition alive Fragments in your List by adding a fragment at 0th index (which causes other fragments to reposition) and ViewPager assigns tags based on position.

Keeping all this in mind, here is a tested and working modified adapter:

public class PagerAdapter extends FragmentPagerAdapter {
public static class FragmentInfo {
    public String classz;
    public ImageFileObject imageFile;


    public static long IDS;
    public long id;

    public FragmentInfo(){
        id = IDS++;
    } 
}



private final List<FragmentInfo> fragments;
private Context context;

public PagerAdapter(FragmentManager fm, List<FragmentInfo> fragments,
        Context context) {
    super(fm);
    this.fragments = fragments;
    this.context = context;
}

@Override
public Fragment getItem(int index) {
    FragmentInfo info = fragments.get(index);
    ImageViewFragment frag = (ImageViewFragment) Fragment.instantiate(
            context, info.classz, /* null arguments*/ null);
    frag.setImage(info.imageFile);
    return frag;
}

@Override
public long getItemId(int position) {
    return fragments.get(position).id;
} 

@Override
public int getCount() {
    return fragments.size();
}

@Override
public int getItemPosition(Object object) {
    return POSITION_NONE;
}

public void add() {
    FragmentInfo f = new FragmentInfo();
    f.classz = ImageViewFragment.class.getName();
    fragments.add(0, f);
    notifyDataSetChanged();
}
}

Please change your code accordingly.

M-WaJeEh
  • 16,562
  • 9
  • 59
  • 93
  • While using your code doesn't throw any errors when adding to the beginning, it still doesn't work. The pages that were visible before adding retain the same indexes, only the previously not loaded pages get updated indexes. If for instance I'm on page 0 and I "prepend" a page, I can not scroll to the left, as the current index is 0, while scrolling to the right gives a duplicate of page 0, since a new instance is created of page 1, which is now the previous page 0... – Ratzor Oct 13 '13 at 17:45
  • I don't understand what you are saying. Are you saying that using this technique just keeps duplicating page 0? Are you sure about this? How are you detecting that scrolling to right gives a duplicate of page 0? – M-WaJeEh Oct 13 '13 at 18:12
  • The problem is, the method doesn't update the already displayed pages. So, if for instance i'm on page 10, prepend a page, and move to page 11, which hasn't instantiated yet, it will show page 10 (which is correct, because i'm requesting a page at index 11, which due to prepending a page is now page 10), the problem is that the page on index 10 remains page 10, because it doesn't re-instantiate. – Ratzor Oct 14 '13 at 05:55
0

The problem is actually with notifyDataSetChanged. Just add to your Adapter:

public int getItemPosition(Object object) {
    return POSITION_NONE;
}

However, I think you will get other problems when the Adapter actually tries to call getItem again. These problems will be in the lines of "Fragment Already Added".

Sherif elKhatib
  • 44,650
  • 15
  • 84
  • 105