We\'re suffering from a very strange issue with ViewPager here. We embed lists on each ViewPager page, and trigger notifyDataSetChanged both on the list adapter and the view
The Android Support Library has a demo Activity that includes a ViewPager with a ListView on every page. You should probably have a look and see what it does.
In Eclipse (with Android Dev Tools r20):
New > Android Sample Project
Support4Demos
Android Tools > Add Support Library
Fragment
and then Pager
The code for this is in src/com.example.android.supportv4.app/FragmentPagerSupport.java
. Good luck!
I ran into this same problem when using a ViewPager and FragmentStatePagerAdapter. I tried using a handler with a 3 second delay to call invalidate() and requestLayout() but it didn't work. What did work was resetting the viewPager's background color as follows:
MyFragment.java
private Handler mHandler;
private Runnable mBugUpdater;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = new ViewPager(getActivity());
//...Create your adapter and set it here...
mHandler = new Handler();
mBugUpdater = new Runnable(){
@Override
public void run() {
mVp.setBackgroundColor(mItem.getBackgroundColor());
mHandler = null;
mBugUpdater = null;
}
};
mHandler.postDelayed(mBugUpdater,50);
return rootView;
}
@Override
public void onPause() {
if(mHandler != null){
//Remove the callback if it hasn't triggered yet
mHandler.removeCallbacks(mBugUpdater);
mHandler = null;
mBugUpdater = null;
}
super.onPause();
}
I had similar issue. I cache views because I need only 3 views in ViewPager
. When I slide forward everything is okay but when I start to slide backward occurs error, it says that "my view already has a parent". The solution is to delete unneeded items manually.
@Override
public Object instantiateItem(ViewGroup container, int position) {
int localPos = position % SIZE;
TouchImageView view;
if (touchImageViews[localPos] != null) {
view = touchImageViews[localPos];
} else {
view = new TouchImageView(container.getContext());
view.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
touchImageViews[localPos] = view;
}
view.setImageDrawable(mDataModel.getPhoto(position));
Log.i(IRViewPagerAdpt.class.toString(), "Add view " + view.toString() + " at pos: " + position + " " + localPos);
if (view.getParent() == null) {
((ViewPager) container).addView(view);
}
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object view) {
// ((ViewPager) container).removeView((View) view);
Log.i(IRViewPagerAdpt.class.toString(), "remove view " + view.toString() + " at pos: " + position);
}
..................
private static final int SIZE = 3;
private TouchImageView[] touchImageViews = new TouchImageView[SIZE];
We finally managed to find a solution. Apparently our implementation suffered of two issues:
destroyItem()
.destroyItem()
, we were not adding it in instantiateItem()
but just returning the cached view corresponding to the current position.I haven't looked too deeply in the source code of the ViewPager
- and it's not exactly explicit that you have to do that - but the docs says :
destroyItem()
Remove a page for the given position. The adapter is responsible for removing the view from its container, although it only must ensure this is done by the time it returns from finishUpdate(ViewGroup).
and:
A very simple PagerAdapter may choose to use the page Views themselves as key objects, returning them from instantiateItem(ViewGroup, int) after creation and adding them to the parent ViewGroup. A matching destroyItem(ViewGroup, int, Object) implementation would remove the View from the parent ViewGroup and isViewFromObject(View, Object) could be implemented as return view == object;.
So my conclusion is that ViewPager
relies on its underlying adapter to explicitly add/remove its children in instantiateItem()
/destroyItem()
. That is, if your adapter is a subclass of PagerAdapter
, your subclass must implement this logic.
Side note: be aware of this if you use lists inside ViewPager
.
Had the same issue, which is something to do with ListView
(because my empty view shows up fine if the list is empty). I just called requestLayout()
on the problematic ListView
. Now it draws fine!
I had the exact same problem but I actually destroyed the view in destroyItem (I thought). The problem however was that I destroyed it using viewPager.removeViewAt(index);
insted of viewPager.removeView((View) object);
Wrong:
@Override
public void destroyItem(ViewGroup viewPager, int position, Object object) {
viewPager.removeViewAt(position);
}
Right:
@Override
public void destroyItem(ViewGroup viewPager, int position, Object object) {
viewPager.removeView((View) object);
}