Fragment already added IllegalStateException in viewpager

混江龙づ霸主 提交于 2019-12-10 14:45:44

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!