131

I am using ViewPager to allow user to swipe between its views. Is there a way how to force this ViewPager to reload/re-instantiate its views in case that they are no longer valid or needs to be refreshed? I tried to call notifyDataSetChanged() on its adapter but this does not invoke instantiateItem() method again.

EDIT

Here is the class that extends from ViewPager and its adapter definision. Bellow is the refresh() method that I call when I want to force to refresh items.

public class DayFlipper extends ViewPager {

public class FlipperAdapter extends PagerAdapter {

    @Override
    public int getCount() {
        return DayFlipper.DAY_HISTORY;
    }

    @Override
    public void startUpdate(View container) {
    }

    @Override
    public Object instantiateItem(View container, int position) {
        Log.d(TAG, "instantiateItem(): " + position);

        Date d = DateHelper.getBot();
        for (int i = 0; i < position; i++) {
            d = DateHelper.getTomorrow(d);
        }

        d = DateHelper.normalize(d);

        CubbiesView cv = new CubbiesView(mContext);
        cv.setLifeDate(d);
        ((ViewPager) container).addView(cv, 0);
        // add map
        cv.setCubbieMap(mMap);
        cv.initEntries(d);
        return cv;
    }

    @Override
    public void destroyItem(View container, int position, Object object) {
        ((ViewPager) container).removeView((CubbiesView) object);
    }

    @Override
    public void finishUpdate(View container) {

    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == ((CubbiesView) object);
    }

    @Override
    public Parcelable saveState() {
        return null;
    }

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) {

    }

}

    ...

    public void refresh() {
    getAdapter().notifyDataSetChanged();
}
}
gordonfreeman
  • 2,485
  • 2
  • 16
  • 13

3 Answers3

174

Had the same problem. For me it worked to call

viewPage.setAdapter( adapter );

again which caused reinstantiating the pages again.

Andi Droid
  • 1,987
  • 2
  • 12
  • 7
89

I have found a solution. It is just a workaround to my problem but currently the only solution.

ViewPager PagerAdapter not updating the View

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

Does anyone know whether this is a bug or not?

Community
  • 1
  • 1
gordonfreeman
  • 2,485
  • 2
  • 16
  • 13
  • 3
    Not really; `getItemPosition` is used to notify the `ViewPager` whether or not to refresh an item, and to avoid updates if the items at the visible positions haven't changed. The "bug" here is the non-obvious and/or non-existent solution to refresh the visible items from client code. – tad Oct 05 '11 at 06:55
  • It sounds like for what you need this for there is no bug in this code. You are basically just saying you need to update each item when a change to the dataset happens. The only difference I would say would be if you want to update only specific pages which would take a bit more logic than this. – Elliott Mar 26 '13 at 15:48
  • for this answer remove r from "gord" .. thanku man. – Tushar Pandey Apr 30 '15 at 06:27
  • 4
    when i refresh the viewpagers data, first two view pagers are not refresh and other view pager data is changing. please help me – kartheeki j Oct 08 '15 at 08:09
  • 3
    this causes java.lang.IllegalStateException: FragmentManager is already executing transactions – Nasz Njoka Sr. Nov 07 '16 at 09:48
  • Do you still have the "smooth" swipe with this solution? – user2399432 Dec 28 '18 at 18:17
4
public class DayFlipper extends ViewPager {

private Flipperadapter adapter;
public class FlipperAdapter extends PagerAdapter {

    @Override
    public int getCount() {
        return DayFlipper.DAY_HISTORY;
    }

    @Override
    public void startUpdate(View container) {
    }

    @Override
    public Object instantiateItem(View container, int position) {
        Log.d(TAG, "instantiateItem(): " + position);

        Date d = DateHelper.getBot();
        for (int i = 0; i < position; i++) {
            d = DateHelper.getTomorrow(d);
        }

        d = DateHelper.normalize(d);

        CubbiesView cv = new CubbiesView(mContext);
        cv.setLifeDate(d);
        ((ViewPager) container).addView(cv, 0);
        // add map
        cv.setCubbieMap(mMap);
        cv.initEntries(d);
adpter = FlipperAdapter.this;
        return cv;
    }

    @Override
    public void destroyItem(View container, int position, Object object) {
        ((ViewPager) container).removeView((CubbiesView) object);
    }

    @Override
    public void finishUpdate(View container) {

    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == ((CubbiesView) object);
    }

    @Override
    public Parcelable saveState() {
        return null;
    }

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) {

    }

}

    ...

    public void refresh() {
    adapter().notifyDataSetChanged();
}
}

try this.

ngesh
  • 13,398
  • 4
  • 44
  • 60
  • 1
    This does not work for me. Just to be sure that we are on same page. I have selected one of x pages that are available to scroll through in `ViewPager`. From menu I invoke action that somehow process data in underlying db and change it. On that page I am presenting that data. By process that I triggered in menu that data were changed. So this change I want to reflect to page I am looking at. It is reflected if I scroll 2 pages out from my current and then return to actual because `instantiateItem()` is triggered but I want to do this without scrolling. – gordonfreeman Sep 12 '11 at 07:04
  • Overriding instantiateItem() is great for if you delete a fragment and then want to add it back. I found this useful for another problem I was having, however not for this one. – Elliott Mar 26 '13 at 15:46