Fragment的getChildFragmentManager

2017-12-27  本文已影响54人  Cursor_fei

前提:

这次项目中采用了在fragment中添加了一个viewpager的形式,viewpager中切换的是fragment。

BUG:

退出了那个包含viewpager的fragment并重新进入,切换viewpager时,不调用fragmentpageradapter适配器的getItem()方法,在显示上,出现viewpager的显示数量增多、显示数据不正确(这个情况只在初始化fragment时,需要传递参数的情况)的情况。

调试:

fragmentpageradapter的instantiateItem(ViewGroup container, int position)方法,在调用的时候做了优化处理:

public Object instantiateItem(ViewGroup container, int position) {
    if (mCurTransaction == null) {
        mCurTransaction = mFragmentManager.beginTransaction();
    }

    final long itemId = getItemId(position);

    // Do we already have this fragment?
    String name = makeFragmentName(container.getId(), itemId);
    Fragment fragment = mFragmentManager.findFragmentByTag(name);
    if (fragment != null) {
        if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
        mCurTransaction.attach(fragment);
    } else {
        fragment = getItem(position);
        if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
        mCurTransaction.add(container.getId(), fragment,
                makeFragmentName(container.getId(), itemId));
    }
    if (fragment != mCurrentPrimaryItem) {
        fragment.setMenuVisibility(false);
        fragment.setUserVisibleHint(false);
    }

    return fragment;
}

以上代码中,会先判断是否已经加载过这个fragment,如果加载过,就只进行attach操作,不会进行实例化,这样可以节约资源。在上面的前提下,debug到这时第二次进入到fragment后,切换内部的fragment时,在此处mFragmentManager.findFragmentByTag(name);方法返回值都不为空,所以导致了上面提到的BUG。

解决:

在实例化FragmentPagerAdapter类时,需要传递两个参数,将第一个参数设置为getChildFragmentManager()而非getFragmentManager()即可解决问题。

fragment源码中有getFragmentManager()的说明:

/**
     * Return the FragmentManager for interacting with fragments associated
     * with this fragment's activity.  Note that this will be non-null slightly
     * before {@link #getActivity()}, during the time from when the fragment is
     * placed in a {@link FragmentTransaction} until it is committed and
     * attached to its activity.
     *
     * <p>If this Fragment is a child of another Fragment, the FragmentManager
     * returned here will be the parent's {@link #getChildFragmentManager()}.
     */
    final public FragmentManager getFragmentManager() {
        return mFragmentManager;
    }

可以理解为:
getFragmentManager()是所在fragment 父容器的碎片管理,
getChildFragmentManager()是在fragment 里面子容器的碎片管理。

上一篇下一篇

猜你喜欢

热点阅读