Viewpager和FragmentPagerAdapter:页面视图删除

10
我正在使用FragmentPagerAdapterViewpager,允许添加和删除页面。每个页面显示从互联网获取的数据。
当添加新页面时,会将新的Fragment与该页面相关联。通过AsyncTask获取数据并在Fragment中展示。当用户选择删除某个页面时,意味着要销毁该页面及其关联的Fragment。
总体来说,这一切都很顺利。我遇到的问题如下:
  1. 你有三个带数据的页面:
  2. [页面 1] [页面 2] [页面 3]

  3. 你删除任何一个页面(除了最后一个),比如页面 2;页面 2 消失了:
  4. [页面 1] [页面 3]

  5. 你添加了一个新页面;但是新页面不是一个空的新页面,它展示了来自页面 3 的数据(视图)。
  6. [页面 1] [页面 3] [页面 4,但显示页面 3 的视图/数据,应该是空白的]

我的活动中的页面删除代码如下:
   // Destroy fragment for this page
   DataListFragment curFrag = getFragmentByName(currentPage);
   FragmentManager fm = getSupportFragmentManager();
   fm.beginTransaction().remove(curFrag).commit();
   fm.executePendingTransactions();
   curFrag = null;

   // Remove page and update adapter
   mPageTitles.remove(position);        
   mAdapter.notifyDataSetChanged();
使用调试器可以看到,在执行了executePendingTransactions()方法后,片段从FragmentManager中被移除。但在FragmentPagerAdaptermAdapter.notifyDataSetChanged()方法中,该片段会被添加回去并在创建新页面时显示出来。
我尝试使用FrameStatePagerAdapter,因为它应该允许销毁片段,但它没有生效。在我的FragmentPagerAdaptergetItemPosition()方法中,我使用了return FragmentAdapter.POSITION_NONE;,正如我在另一篇SO文章中发现的那样。
似乎该页面的视图并没有被销毁,而是被添加回了新页面中。我尝试在新页面的视图上使用removeViewAt()方法,但这并没有起作用。
作为一个新手,我肯定错过了一些显而易见的东西...

我不确定这是否是显而易见的事情。我也遇到了这个问题。你解决了吗?这里可能有一个答案:https://dev59.com/cGcs5IYBdhLWcg3w3Hyn - Robert Karl
1
你能展示一下你重写的方法吗:public Fragment getItem(int position)? - Gomino
当你移除一个片段时,你不是从适配器中移除它。这就是为什么它会再次出现的原因。你需要从适配器中移除它(不是视图,而是在getItem()方法中使用的项目)。第四个片段看起来像第三个,因为它重用了片段,就像ListView的适配器一样。你在适配器逻辑上犯了一个错误。请展示你的适配器类。 - Alexander Mikhaylov
3个回答

1
你应该扩展FragmentStatePagerAdapter并从该适配器的项目列表中删除相应的项目,而不是尝试从活动中删除片段。在适配器中删除项目后,不要忘记调用adapter.notifyDataSetChanged()。完成后,ViewPagerFragmentStatePagerAdapter将处理其余部分。

0

看到你的getCount()方法返回了viewPager中确切的项目数量。而且,FragmentStatePagerAdapter也会计算在内。


0

我找到了一个解决方案,结合了以下根据经验得出的知识:

  • 你可以在末尾添加新的Fragment而不会出现问题。
  • 你不能重新添加之前删除的Fragment,因为有时会导致java.lang.IllegalStateException: Can't change tag of fragment,所以你必须克隆它。
  • 要删除Fragment,你必须在方法getItemPosition(Object object)中返回PagerAdapter.POSITION_NONE,并从FragmentManager中删除Fragment
  • 如果你在除末尾以外的其他位置添加/删除/替换,则必须从你正在更改的位置开始一直删除到末尾,然后做你需要做的事情,然后重新添加(克隆)你删除的Fragment

这里有一个完整的FragmentActivity代码以及一个FragmentPagerAdapter,其中包含3种添加、删除和替换选项卡的方法:

public class TabTestActivity extends FragmentActivity implements
        ActionBar.TabListener {
    private SectionsPagerAdapter mSectionsPagerAdapter;
    private ViewPager mViewPager;
    private static int tabCount = 0;
    private static String labelString = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        labelString = getString(R.string.title_section);
        setContentView(R.layout.activity_tab_test);
        final ActionBar actionBar = getActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        mSectionsPagerAdapter = new SectionsPagerAdapter(
                getSupportFragmentManager());
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mSectionsPagerAdapter);
        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                    @Override
                    public void onPageSelected(final int position) {
                        (new Handler()).postDelayed(new Runnable() {

                            @Override
                            public void run() {
                                actionBar.setSelectedNavigationItem(position);
                            }

                        }, 1);
                    }
                });

        for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
            actionBar.addTab(actionBar.newTab()
                    .setText(mSectionsPagerAdapter.getPageTitle(i))
                    .setTabListener(this));
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.tab_test, menu);
        return true;
    }

    public void addNewTab() {
        int position = (mSectionsPagerAdapter.getCount() > 0 ? mViewPager.getCurrentItem() : 0);
        mSectionsPagerAdapter.insertFragment(position);
        mViewPager.setCurrentItem(position, true);
    }

    public void removeTab() {
        if (mSectionsPagerAdapter.getCount() > 0) {
            int position = mViewPager.getCurrentItem();
            mSectionsPagerAdapter.removeFragment(position);
        }
    }

    public void replaceTab() {
        if (mSectionsPagerAdapter.getCount() > 0) {
            int position = mViewPager.getCurrentItem();
            mSectionsPagerAdapter.replaceFragment(position);            
            mViewPager.setCurrentItem(position, false);
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.action_add_tab:
            addNewTab();
            return true;
        case R.id.action_remove_tab:
            removeTab();
            return true;
        case R.id.action_replace_tab:
            replaceTab();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onTabSelected(ActionBar.Tab tab,
            FragmentTransaction fragmentTransaction) {
        mViewPager.setCurrentItem(tab.getPosition());
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab,
            FragmentTransaction fragmentTransaction) {
    }

    @Override
    public void onTabReselected(ActionBar.Tab tab,
            FragmentTransaction fragmentTransaction) {
    }

    public class SectionsPagerAdapter extends FragmentPagerAdapter {

        private List<Fragment> currentFragments;
        private FragmentManager fragmentManager;

        public SectionsPagerAdapter(FragmentManager fm) {
            super(fm);
            fragmentManager = fm;
            currentFragments = new ArrayList<Fragment>();
        }

        public void insertFragment(int position) {
            // Remove fragments from position
            List<Fragment> fragmentsToRemove = new ArrayList<Fragment>(currentFragments.subList(position, currentFragments.size()));
            int i = currentFragments.size() - 1;
            int j = -1;
            int k = i;
            while (i >= position) {
                currentFragments.remove(i);
                i--;
                j++;
            }
            notifyDataSetChanged();
            final ActionBar actionBar = getActionBar();
            while (k >= position) {
                actionBar.removeTabAt(k);
                k--;
            }
            android.support.v4.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
            while (j >= 0) {
                Fragment fragmentToRemove = fragmentsToRemove.get(j);
                transaction.detach(fragmentToRemove);
                transaction.remove(fragmentToRemove);
                j--;
            }
            transaction.commit();
            fragmentManager.executePendingTransactions();
            notifyDataSetChanged();
            // Add new fragment
            Fragment fragment = new DummySectionFragment();
            currentFragments.add(position, fragment);
            notifyDataSetChanged();
            actionBar.addTab(actionBar.newTab()
                    .setText(mSectionsPagerAdapter.getPageTitle(position))
                    .setTabListener(TabTestActivity.this), position);
            // Readd fragments
            if (fragmentsToRemove.size() > 0) {
                i = 1;
                for (Fragment fragmentToRemove : fragmentsToRemove) {
                    currentFragments.add(DummySectionFragment.cloneExistingFragment((DummySectionFragment)fragmentToRemove));
                    notifyDataSetChanged();
                    actionBar.addTab(actionBar.newTab()
                            .setText(mSectionsPagerAdapter.getPageTitle(position + i))
                            .setTabListener(TabTestActivity.this), position + i);
                    i++;
                }
            }
        }

        public void removeFragment(int position) {
            // Remove fragments from position
            List<Fragment> fragmentsToRemove = new ArrayList<Fragment>(currentFragments.subList(position, currentFragments.size()));
            int i = currentFragments.size() - 1;
            int j = -1;
            int k = i;
            while (i >= position) {
                currentFragments.remove(i);
                i--;
                j++;
            }
            notifyDataSetChanged();
            final ActionBar actionBar = getActionBar();
            while (k >= position) {
                actionBar.removeTabAt(k);
                k--;
            }
            android.support.v4.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
            while (j >= 0) {
                Fragment fragmentToRemove = fragmentsToRemove.get(j);
                transaction.detach(fragmentToRemove);
                transaction.remove(fragmentToRemove);
                j--;
            }
            transaction.commitAllowingStateLoss();
            fragmentManager.executePendingTransactions();
            notifyDataSetChanged();
            // Readd fragments (except one)
            if (fragmentsToRemove.size() > 1) {
                i = 0;
                for (Fragment fragment : fragmentsToRemove.subList(1, fragmentsToRemove.size())) {
                    currentFragments.add(DummySectionFragment.cloneExistingFragment((DummySectionFragment)fragment));
                    notifyDataSetChanged();
                    actionBar.addTab(actionBar.newTab()
                            .setText(mSectionsPagerAdapter.getPageTitle(position + i))
                            .setTabListener(TabTestActivity.this), position + i);
                    i++;
                }
            }
        }

        public void replaceFragment(int position) {
            // Remove fragments from position
            List<Fragment> fragmentsToRemove = new ArrayList<Fragment>(currentFragments.subList(position, currentFragments.size()));
            int i = currentFragments.size() - 1;
            int j = -1;
            int k = i;
            while (i >= position) {
                currentFragments.remove(i);
                i--;
                j++;
            }
            notifyDataSetChanged();
            final ActionBar actionBar = getActionBar();
            while (k >= position) {
                actionBar.removeTabAt(k);
                k--;
            }
            android.support.v4.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
            while (j >= 0) {
                Fragment fragmentToRemove = fragmentsToRemove.get(j);
                transaction.detach(fragmentToRemove);
                transaction.remove(fragmentToRemove);
                j--;
            }
            transaction.commit();
            fragmentManager.executePendingTransactions();
            notifyDataSetChanged();
            // Add new fragment
            Fragment fragment = new DummySectionFragment();
            currentFragments.add(position, fragment);
            notifyDataSetChanged();
            actionBar.addTab(actionBar.newTab()
                    .setText(mSectionsPagerAdapter.getPageTitle(position))
                    .setTabListener(TabTestActivity.this), position);
            // Readd fragments (except one)
            if (fragmentsToRemove.size() > 0) {
                i = 1;
                for (Fragment fragmentToRemove : fragmentsToRemove.subList(1, fragmentsToRemove.size())) {
                    currentFragments.add(DummySectionFragment.cloneExistingFragment((DummySectionFragment)fragmentToRemove));
                    notifyDataSetChanged();
                    actionBar.addTab(actionBar.newTab()
                            .setText(mSectionsPagerAdapter.getPageTitle(position + i))
                            .setTabListener(TabTestActivity.this), position + i);
                    i++;
                }
            }
        }

        @Override
        public Fragment getItem(int position) {
            if (currentFragments == null) {
                currentFragments = new ArrayList<Fragment>();
            }
            while (currentFragments.size() <= position) {
                currentFragments.add(null);
            }
            if (currentFragments.get(position) != null) {
                return currentFragments.get(position);
            }
            Fragment fragment = new DummySectionFragment();
            currentFragments.set(position, fragment);
            return fragment;
        }

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

        @Override
        public int getItemPosition(Object object) {
            int position = currentFragments.indexOf(object);
            if (position == -1) {
                return PagerAdapter.POSITION_NONE;
            }
            return position;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return ((DummySectionFragment)getItem(position)).getTitle();
        }
    }

    public static class DummySectionFragment extends Fragment {
        private int sectionNumber;

        public DummySectionFragment() {
            super();
            sectionNumber = ++tabCount;
        }

        public static DummySectionFragment cloneExistingFragment(DummySectionFragment fragment) {
            DummySectionFragment cloned = new DummySectionFragment();
            // Hack for avoiding autoincrement
            --tabCount;
            cloned.sectionNumber = fragment.getSectionNumber();
            return cloned;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_tab_test_dummy,
                    container, false);
            TextView dummyTextView = (TextView) rootView
                    .findViewById(R.id.section_label);
            dummyTextView.setText(String.format(labelString, sectionNumber));
            return rootView;
        }

        public int getSectionNumber() {
            return sectionNumber;
        }

        public String getTitle() {
            return String.format(labelString, sectionNumber);
        }
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接