FragmentStatePagerAdapter

FragmentStatePagerAdapter

我在Android应用中遇到了非常难以诊断的问题。当getUserVisibleHint()应该返回true(因为它是可见的并且被选中)时,它会在false中返回当前所选 fragment 上的ViewPager

我对实例的特征进行了描述,如下所示:

  • fragment 已选择,当前显示在ViewPager
  • ViewPager由FragmentStatePagerAdapter
  • 管理
  • fragment 是先前选择的,其状态已保存,后来由PagerAdapter恢复
  • viewpager中至少3个标签页
  • 用户导航至选项卡3,然后导航至选项卡1,然后返回至选项卡3。
  • 应用程序使用支持库版本24.0.0或更高版本
  • 最佳答案

    调试显示FragmentStatePagerAdapter实际上在setPrimaryItem(ViewGroup container, int position, Object object)中正确设置了所选选项卡的状态,但后来在FragmentManager#moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive)中将其设置为false

    //from FragmentManager#moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive)
    f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
            FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
    
    上面的f.mSavedFragmentState已将可见状态另存为false,因为在 fragment 不再出现在屏幕上时已将其保存。
    因此,这里的问题是状态丢失;可见状态已在FragmentStatePagerAdapter#setPrimaryItem中设置,但在调用 fragment 的onResume方法之前已丢失了一段时间。
    修复
    在库中修复此错误之前,请在setPrimaryItem中覆盖PagerAdapter并强制所有未决事务首先提交。
    public static class SectionsPagerAdapter extends FragmentStatePagerAdapter {
        public SectionsPagerAdapter(FragmentManager fm) {
            super(fm);
        }
    
        @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            //Force any pending transactions to save before we set an item as primary
            finishUpdate(null);
            super.setPrimaryItem(container, position, object);
        }
    
        @Override
        public Fragment getItem(int position) {
            Fragment fragment = new DummySectionFragment();
            Bundle args = new Bundle();
            args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
            fragment.setArguments(args);
            return fragment;
        }
    
        @Override
        public int getCount() {
            return 4;
        }
    
        @Override
        public CharSequence getPageTitle(int position) {
            return "Page " + (position + 1);
        }
    }
    
    要解决此问题,FragmentStatePagerAdapter必须在设置用户可见提示之前提交任何 fragment 事务。FragmentStatePagerAdapter只是为了显示FragmentStatePagerAdapter内部发生的事情
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        // If we already have this item instantiated, there is nothing
        // to do.  This can happen when we are restoring the entire pager
        // from its saved state, where the fragment manager has already
        // taken care of restoring the fragments we previously had instantiated.
        if (mFragments.size() > position) {
            Fragment f = mFragments.get(position);
            if (f != null) {
                return f;
            }
        }
    
        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }
    
        Fragment fragment = getItem(position);
        if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
        if (mSavedState.size() > position) {
            Fragment.SavedState fss = mSavedState.get(position);
            if (fss != null) {
                fragment.setInitialSavedState(fss);
            }
        }
        while (mFragments.size() <= position) {
            mFragments.add(null);
        }
        fragment.setMenuVisibility(false);
        fragment.setUserVisibleHint(false);
        mFragments.set(position, fragment);
        mCurTransaction.add(container.getId(), fragment);
    
        return fragment;
    }
    
    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        Fragment fragment = (Fragment)object;
        if (fragment != mCurrentPrimaryItem) {
            if (mCurrentPrimaryItem != null) {
                mCurrentPrimaryItem.setMenuVisibility(false);
                mCurrentPrimaryItem.setUserVisibleHint(false);
            }
            if (fragment != null) {
                fragment.setMenuVisibility(true);
                fragment.setUserVisibleHint(true);
            }
            mCurrentPrimaryItem = fragment;
        }
    }
    
    @Override
    public void finishUpdate(ViewGroup container) {
        if (mCurTransaction != null) {
            mCurTransaction.commitNowAllowingStateLoss();
            mCurTransaction = null;
        }
    }
    

    关于android - 在由FragmentStatePagerAdapter管理的选定ViewPager Fragment上,UserVisibleHint为false,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44052437/

    10-10 02:07