问题
I'm using viewpager to display pictures. I just need three fragments basically: previous image to preview, current display image and next image to preview. I would like to just display a preview of previous and next image, it will change to full image when user actually swipe to it. So I'm thinking of just using 3 fragment to achieve this. Code is below:
private class ImagePagerAdapter extends FragmentStatePagerAdapter implements ViewPager.OnPageChangeListener {
private ImageFragment mImageFragment;
private ImagePreviewFragment mPreviousPreviewFragment;
private ImagePreviewFragment mNextPreviewFragment;
public ImagePagerAdapter(FragmentManager fm, ImageFragment image, ImagePreviewFragment previous, ImagePreviewFragment next) {
super(fm);
mImageFragment = image;
mPreviousPreviewFragment = previous;
mNextPreviewFragment = next;
}
@Override
public Fragment getItem(int position) {
if (position == mPager.getCurrentItem()) {
mImageFragment.display(position);
return mImageFragment;
}
if (position < mPager.getCurrentItem()) {
mPreviousPreviewFragment.display(position - 1);
return mPreviousPreviewFragment;
}
mNextPreviewFragment.display(position + 1);
return mNextPreviewFragment;
}
@Override
public int getCount() {
return 100;
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
Log.d(TAG, "onPageScrolled");
}
@Override
public void onPageSelected(final int position) {
Log.d(TAG, "onPageSelected " + position);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
notifyDataSetChanged();
}
}, 500);
}
@Override
public void onPageScrollStateChanged(int state) {
Log.d(TAG, "onPageScrollStateChanged " + state);
}
@Override
public int getItemPosition(Object item) {
return POSITION_NONE;
//return POSITION_UNCHANGED;
}
}
So basically, I pre-created three fragments to display previous/next preview and current image and return them for getItem(). I also notifydatasetchange() in onpageselected() to make all three position to update the fragment when user swipe to new page.
But the problem is that it will throw out
Fragment already added IllegalStateException
when the fragments are added a second time. I think it's because it's been added before. I can create a new fragment every time but I think that's wasteful. So how can I reuse the already created fragment and just update them?
Thanks, Simon
回答1:
FragmentStatePagerAdapter
design suggests creating a new Fragment
for every page (see Google's example). And unfortunately you cannot readd a Fragment
once it was added to a FragmentManager
(what implicitly happens inside adapter), hence the exception you're facing with. So the official Google-way is to create new fragments and let them be destroyed and recreated by the adapter.
But if you want to reuse pages and utilize an analogue of ViewHolder pattern, you should stick to views instead of fragments. Views could be removed from their parent and reused, unlike fragments. Extend PagerAdapter
and implement instantiateItem()
like this:
@Override
public Object instantiateItem(ViewGroup container, final int position) {
//determine the view type by position
View view = viewPager.findViewWithTag("your_view_type");
if (view == null) {
Context context = container.getContext();
view = LayoutInflater.from(context).inflate(R.layout.page, null);
view.setTag("your_view_type");
} else {
ViewGroup parent = (ViewGroup) item.getParent();
if (parent != null) {
parent.removeView(item);
}
}
processYourView(position, view);
container.addView(view, MATCH);
return view;
}
You should add some extra logic to determine the view type by position (since you have 3 types of views), I think you can figure that out.
来源:https://stackoverflow.com/questions/30293192/fragment-already-added-illegalstateexception-in-viewpager