onCreateView 并不总是在 viewPagerAdapter.addTab() 之后调用

onCreateView is not always called after viewPagerAdapter.addTab()

我想创建带有动态 add/remove 选项卡选项的应用程序,但我遇到了一件事。

当我第一次添加标签时,一切正常,但是当我删除一个标签并想再次添加新标签时,没有在该新片段上调用 ​​onCreateView。

示例:

我添加了 3 个新标签:

ViewPagerAdapter vpa = (ViewPagerAdapter) mViewPager.getAdapter();
vpa.addTab("TAB 1");
vpa.notifyDataSetChanged();

onCreateView 被调用。

some logs:
    [add tab] mViewPager.getChildCount() = 1
    [add tab] vpa.getCount() = 1
vpa.addTab("TAB 2");
vpa.notifyDataSetChanged();

onCreateView 被调用。

some logs:
    [add tab] mViewPager.getChildCount() = 2
    [add tab] vpa.getCount() = 2
vpa.addTab("TAB 3");
vpa.notifyDataSetChanged();

onCreateView 被调用。

some logs:
    [add tab] mViewPager.getChildCount() = 3
    [add tab] vpa.getCount() = 3
vpa.removeTab("TAB 2");
vpa.notifyDataSetChanged();
some logs:
    [add tab] mViewPager.getChildCount() = 2
    [add tab] vpa.getCount() = 2
vpa.addTab("TAB 2");
vpa.notifyDataSetChanged();

并且没有调用 onCreateView :(

some logs:
    [add tab] mViewPager.getChildCount() = 2
    [add tab] vpa.getCount() = 3

有人知道怎么解决吗?为什么不总是调用 onCreateView?

应用代码:

private void initViewpagerAndTabs(){
    mViewPager = (ViewPager) findViewById(R.id.viewpager_slave);
    mViewPager.setOffscreenPageLimit(10);
    mAdapterViewPager = new ViewPagerAdapter(getSupportFragmentManager());
    mViewPager.setAdapter(mAdapterViewPager);
    mTabLayout = (TabLayout) findViewById(R.id.tabLayout_slave);
    mTabLayout.setupWithViewPager(mViewPager);
}
/** Tabs content fragment */
public static class DummyFragment extends Fragment implements RecyclerAdapter.ViewHolder.ClickListener {
    private RecyclerView mRecyclerView;
    private RecyclerAdapter mAdapterRecycler;
    private RecyclerView.LayoutManager mLayoutManager;
    private Fab fab;

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.content_slave, container, false);

        //setRetainInstance(true);
        initRecyclerView(view);
        fab = (Fab) getActivity().findViewById(R.id.fabRemoveItems);

        return view;
    }

    private void initRecyclerView(View view){
        mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view_slave);

        // use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView
        mRecyclerView.setHasFixedSize(true);

        mLayoutManager = new LinearLayoutManager(getContext());
        mRecyclerView.setLayoutManager(mLayoutManager);
        RecyclerView.ItemAnimator itemAnimator = mRecyclerView.getItemAnimator();
        itemAnimator.setAddDuration(500);
        itemAnimator.setRemoveDuration(500);

        mAdapterRecycler = new RecyclerAdapter(this);
        mRecyclerView.setAdapter(mAdapterRecycler);
    }

}
private class ViewPagerAdapter extends FragmentStatePagerAdapter {
    private final List<DummyFragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    public DummyFragment getItem(int num) throws IndexOutOfBoundsException{
        return mFragmentList.get(num);
    }

    public void addTab(String title) throws Exception {
        if(isTabExist(title)){
            throw new Exception("Tabs already exist!");
        }
        //Log.d(TAG, "[addTab] mFragmentTitleList before add: " + mFragmentTitleList);
        //Log.d(TAG, "[addTab] mFragmentList before add: " + mFragmentList);
        mFragmentList.add(new DummyFragment());
        mFragmentTitleList.add(title);
        //Log.d(TAG, "[addTab] mFragmentTitleList after add: " + mFragmentTitleList);
        //Log.d(TAG, "[addTab] mFragmentList after add: " + mFragmentList);
    }

    public void removeTab(int position){
        //Log.d(TAG, "[removeTab] mFragmentTitleList before removed: " + mFragmentTitleList);
        //Log.d(TAG, "[removeTab] mFragmentList before removed: " + mFragmentList);
        mFragmentTitleList.remove(position);
        mFragmentList.remove(position);
        //Log.d(TAG, "[removeTab] mFragmentTitleList after removed: " + mFragmentTitleList);
        //Log.d(TAG, "[removeTab] mFragmentList after removed: " + mFragmentList);
    }

    private boolean isTabExist(String name){
        for(int i = 0; i < mFragmentTitleList.size(); i++) {
            if (mFragmentTitleList.get(i).equals(name)) {
                return true;
            }
        }
        return false;
    }

    public int getTabPosition(String tabName) throws IndexOutOfBoundsException{
        for(int i = 0; i < mFragmentTitleList.size(); i++) {
            if (mFragmentTitleList.get(i).equals(tabName)) {
                return i;
            }
        }
        throw new IndexOutOfBoundsException();
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        super.destroyItem(container, position, object);
      getSupportFragmentManager().beginTransaction().remove((Fragment) object)
                .commit();
    }

    @Override
    public int getItemPosition(Object object) {
        if (mFragmentList.contains(object)) return mFragmentList.indexOf(object);
        else return POSITION_NONE;
    }

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

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitleList.get(position);
    }
}

好的,我解决了这个问题。

删除:

mViewPager.setOffscreenPageLimit(10);

覆盖保存片段状态的方法:

public void onViewStateRestored(@Nullable Bundle savedInstanceState)

public void onSaveInstanceState(Bundle outState)

我还创建了自己的 FragmentStatePagerAdapter class。我需要不在已删除的选项卡上保存片段状态。

代码:

public class FragStatePagerAdaper extends PagerAdapter {

    private static final String TAG = "FragStatePagerAdapter";
    private static final boolean DEBUG = true;

    private final FragmentManager mFragmentManager;
    private FragmentTransaction mCurTransaction = null;

    private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
    /** Cached fragments */
    private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
    private Fragment mCurrentPrimaryItem = null;

    private List<DummyFragment> mFragmentList = new ArrayList<>();
    private List<String> mFragmentTitleList = new ArrayList<>();

    public FragStatePagerAdaper(FragmentManager fm) {
        mFragmentManager = fm;
    }

    /**
     * Return the Fragment associated with a specified position.
     */
    public DummyFragment getItem(int num) throws IndexOutOfBoundsException{
        return mFragmentList.get(num);
    }

    @Override
    public void startUpdate(ViewGroup container) {
    }

    @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 destroyItem(ViewGroup container, int position, Object object) {
        Fragment fragment = (Fragment) object;

        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }
        if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object
                + " v=" + ((Fragment)object).getView());
        while (mSavedState.size() <= position) {
            mSavedState.add(null);
        }

        mSavedState.set(position, fragment.isAdded()
                    ? mFragmentManager.saveFragmentInstanceState(fragment) : null);

        mFragments.set(position, null);

        mCurTransaction.remove(fragment);
    }

    public void addTab(String title) throws Exception {
        if(isTabExist(title)){
            throw new Exception("Tabs already exist!");
        }
        mFragmentList.add(new DummyFragment());
        mFragmentTitleList.add(title);
    }

    //look here!
    public void removeTab(int position){
        Log.d(TAG, "removeTab: position = " + position);
        mFragmentTitleList.remove(position);
        mFragmentList.remove(position);
        mSavedState.remove(position);  // <---- here!
    }

    private boolean isTabExist(String name){
        for(int i = 0; i < mFragmentTitleList.size(); i++) {
            if (mFragmentTitleList.get(i).equals(name)) {
                return true;
            }
        }
        return false;
    }

    public int getTabPosition(String tabName) throws IndexOutOfBoundsException{
        for(int i = 0; i < mFragmentTitleList.size(); i++) {
            if (mFragmentTitleList.get(i).equals(tabName)) {
                return i;
            }
        }
        throw new IndexOutOfBoundsException();
    }

    @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.commitAllowingStateLoss();
            mCurTransaction = null;
            mFragmentManager.executePendingTransactions();
        }

        ArrayList<Fragment> update = new ArrayList<Fragment>();
        for (int i=0, n=mFragments.size(); i < n; i++) {
            Fragment f = mFragments.get(i);
            if (f == null) continue;
            int pos = getItemPosition(f);
            while (update.size() <= pos) {
                update.add(null);
            }
            update.set(pos, f);
        }
        mFragments = update;
    }


    @Override
    public boolean isViewFromObject(View view, Object object) {
        return ((Fragment)object).getView() == view;
    }

    @Override
    public Parcelable saveState() {
        Bundle state = null;
        if (mSavedState.size() > 0) {
            state = new Bundle();
            Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
            mSavedState.toArray(fss);
            state.putParcelableArray("states", fss);
        }
        for (int i=0; i<mFragments.size(); i++) {
            Fragment f = mFragments.get(i);
            if (f != null && f.isAdded()) {
                if (state == null) {
                    state = new Bundle();
                }
                String key = "f" + i;
                mFragmentManager.putFragment(state, key, f);
            }
        }
        return state;
    }

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) {
        if (state != null) {
            Bundle bundle = (Bundle)state;
            bundle.setClassLoader(loader);
            Parcelable[] fss = bundle.getParcelableArray("states");
            mSavedState.clear();
            mFragments.clear();
            if (fss != null) {
                for (int i=0; i<fss.length; i++) {
                    mSavedState.add((Fragment.SavedState)fss[i]);
                }
            }
            Iterable<String> keys = bundle.keySet();
            for (String key: keys) {
                if (key.startsWith("f")) {
                    int index = Integer.parseInt(key.substring(1));
                    Fragment f = mFragmentManager.getFragment(bundle, key);
                    if (f != null) {
                        while (mFragments.size() <= index) {
                            mFragments.add(null);
                        }
                        f.setMenuVisibility(false);
                        mFragments.set(index, f);
                    } else {
                        Log.w(TAG, "Bad fragment at key " + key);
                    }
                }
            }
        }
    }

    @Override
    public int getItemPosition(Object object) {
        if (mFragmentList.contains(object)) return mFragmentList.indexOf(object);
        else return POSITION_NONE;
    }

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

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitleList.get(position);
    }

}

您好!