FragmentStatePagerAdapter,childFragmentManager和orientation更改了一个坏的组合?

时间:2014-05-23 22:28:37

标签: java android android-fragments android-viewpager fragmentstatepageradapter

这是我的问题,我有一个活动,其中包含一个使用ViewPager的Fragment(FragmentStatePagerAdapter),当Activity首次加载时,所有工作都很完美,但是当设置setRetainInstance(true)到父片段时(带有寻呼机的那个),并且活动的方向发生变化,它会导致

  

java.lang.IllegalStateException:No activity

尝试添加已保存的片段时,代码如下:

的活动:

public class DetailActivity{

...
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.frame_layout_with_progress_container);

    ...

    // However, if we're being restored from a previous state,
    // then we don't need to do anything and should return or else
    // we could end up with overlapping fragments.
    FragmentManager fm = getSupportFragmentManager();
    if (savedInstanceState != null) {
        Fragment f = fm.findFragmentById(R.id.container);
        if(f instanceof DetailPagerFragment){
            detailPagerFragment = (DetailPagerFragment) f;
        }
    }
}

@Override
protected void onPostResume() {
    super.onPostResume();

    //If fragment is null, create a new instance
    if(detailPagerFragment==null){
        detailPagerFragment =
            DetailContainerFragment.newInstance(details, initialPosition);
    }

    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.replace(R.id.container, detailPagerFragment);
    ft.commit();
}

注意:我必须在onCreate上保存片段实例,因为当代码到达onStart时,此片段的引用为null(此问题与它有关的时间并不重要NavigationDrawer),所以我需要手动保存片段的实例。

活动布局:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/container"/>

</RelativeLayout>

ViewPager Fragmentm此类扩展为DetailPagerFragment,它是一个自定义的分页器片段,它只包含寻呼机的公共代码(例如视图膨胀,使用inflateView方法),这就是为什么寻呼机被添加到片段上而不是直接参加活动

public class DetailContainerFragment extends DetailPagerFragment {

    List<Detail> details;

    public static DetailContainerFragment newInstance(List<Detail> details,int selectedPosition) {
        DetailContainerFragment df = new DetailContainerFragment();
        df.setSelectedPosition(selectedPosition);
        df.setDetails(details);
        return df;
    }

    public void setDetails(List<Detail> details) {
        this.details = details;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }


    /**
     * Inflates the view to be used by this fragment
     *
     * @param inflater
     *  Inflater to use
     * @return Inflated view
     */
    @Override
    public View inflateView(LayoutInflater inflater) {
        return inflater.inflate(R.layout.detail_pager_fragment, null);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        DetailStatePagerAdapter detailStatePagerAdapter = new DetailStatePagerAdapter(getChildFragmentManager());
        setPagerAdapter(detailStatePagerAdapter);
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    private class DetailStatePagerAdapter extends FragmentStatePagerAdapter {

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

        @Override
        public Fragment getItem(int position) {
            return DetailFragment.newInstance(details.get(position));
        }

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

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

1 个答案:

答案 0 :(得分:6)

我在ViewPager中遇到了与子片段类似的问题。

父片段创建了与ViewPager一起使用的子片段的新实例,而适配器保留了在配置更改之前使用的旧子片段的实例。

在用它初始化适配器之前,我最终清理了ChildFragmentManager:

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    mPager = (ViewPager) view.findViewById(R.id.pager);

    cleanChildFragments(getChildFragmentManager());

    mPagerAdapter = new MyPagerAdapter(getChildFragmentManager(), getTabFragments());
    mPager.setAdapter(mPagerAdapter);
}

/**
 * This is necessary to have a clean ChildFragmentManager, old fragments might be called otherwise
 * @param childFragmentManager
 */
private void cleanChildFragments(FragmentManager childFragmentManager) {
    List<Fragment> childFragments = childFragmentManager.getFragments();
    if (childFragments != null && !childFragments.isEmpty()) {
        FragmentTransaction ft = childFragmentManager.beginTransaction();
        for (Fragment fragment : childFragments) {
            ft.remove(fragment);
        }
        ft.commit();
    }
}

也许这有助于某人...