如何使用ViewPager和嵌套片段正确处理屏幕旋转?

Ben*_*fez 30 android android-adapter android-fragments android-viewpager

我有这个活动,它有一个片段.这个片段布局包含一个带有几个片段的视图寻呼机(实际上是两个片段).

创建视图寻呼机时,会创建其适配器,getItem调用它并创建子片段.大.

现在,当我旋转屏幕时,框架处理片段重新创建,适配器在我onCreate的主片段中再次创建,但getItem永远不会被调用,因此我的适配器保存错误的引用(实际上为空)而不是两个片段.

我发现片段管理器(即子片段管理器)包含一个被调用的片段数组mActive,当然这些片段无法从代码中访问.但是有这种getFragment方法:

@Override
public Fragment getFragment(Bundle bundle, String key) {
    int index = bundle.getInt(key, -1);
    if (index == -1) {
        return null;
    }
    if (index >= mActive.size()) {
        throwException(new IllegalStateException("Fragement no longer exists for key "
                + key + ": index " + index));
    }
    Fragment f = mActive.get(index);
    if (f == null) {
        throwException(new IllegalStateException("Fragement no longer exists for key "
                + key + ": index " + index));
    }
    return f;
}
Run Code Online (Sandbox Code Playgroud)

我不会评论拼写错误:)
这是我在我的适配器构造函数中为了更新对我的片段的引用而实现的hack:

// fm holds a reference to a FragmentManager
Bundle hack = new Bundle();
try {
    for (int i = 0; i < mFragments.length; i++) {
        hack.putInt("hack", i);
        mFragments[i] = fm.getFragment(hack, "hack");
    }
} catch (Exception e) {
    // No need to fail here, likely because it's the first creation and mActive is empty
}
Run Code Online (Sandbox Code Playgroud)

我并不自豪.这有效,但很难看.在屏幕旋转后拥有有效适配器的实际方法是什么?

PS:这是完整的代码

Jos*_*unt 28

我有同样的问题 - 我假设你是FragmentPagerAdapter你的寻呼机适配器的子类(getItem()具体到FragmentPagerAdapter).

我的解决方案是自己子类化PagerAdapter并自己处理片段创建/删除(重新实现一些FragmentPagerAdapter代码):

public class ListPagerAdapter extends PagerAdapter {
    FragmentManager fragmentManager;
    Fragment[] fragments;

    public ListPagerAdapter(FragmentManager fm){
        fragmentManager = fm;
        fragments = new Fragment[5];
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        assert(0 <= position && position < fragments.length);
        FragmentTransaction trans = fragmentManager.beginTransaction();
        trans.remove(fragments[position]);
        trans.commit();
        fragments[position] = null;
}

    @Override
    public Fragment instantiateItem(ViewGroup container, int position){
        Fragment fragment = getItem(position);
        FragmentTransaction trans = fragmentManager.beginTransaction();
        trans.add(container.getId(),fragment,"fragment:"+position);
        trans.commit();
        return fragment;
    }

    @Override
    public int getCount() {
        return fragments.length;
    }

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

    public Fragment getItem(int position){
        assert(0 <= position && position < fragments.length);
        if(fragments[position] == null){
            fragments[position] = ; //make your fragment here
        }
        return fragments[position];
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.

  • 是的,我花了3年时间才接受你的解决方案.谢谢!:d (3认同)

sim*_*dam 6

我的回答有点类似于Joshua Hunt的回答,但是通过提交finishUpdate方法可以获得更好的性能.一次交易而不是每次更新两次.这是代码:

private class SuchPagerAdapter extends PagerAdapter{

    private final FragmentManager mFragmentManager;
    private SparseArray<Fragment> mFragments;
    private FragmentTransaction mCurTransaction;

    private SuchPagerAdapter(FragmentManager fragmentManager) {
        mFragmentManager = fragmentManager;
        mFragments = new SparseArray<>();
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment = getItem(position);
        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }
        mCurTransaction.add(container.getId(),fragment,"fragment:"+position);
        return fragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }
        mCurTransaction.detach(mFragments.get(position));
        mFragments.remove(position);
    }

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

    public Fragment getItem(int position) {         
        return YoursVeryFragment.instantiate();
    }

    @Override
    public void finishUpdate(ViewGroup container) {
        if (mCurTransaction != null) {
            mCurTransaction.commitAllowingStateLoss();
            mCurTransaction = null;
            mFragmentManager.executePendingTransactions();
        }
    }


    @Override
    public int getCount() {
        return countOfPages;
    }

}
Run Code Online (Sandbox Code Playgroud)


小智 6

为什么解决方案如此复杂?看起来有点矫枉过正.我解决它只是将旧的引用替换为FragmentPagerAdapter中扩展的new类

 @Override
public Object instantiateItem(ViewGroup container, int position) {
    frags[position] = (Fragment) super.instantiateItem(container, position);
    return frags[position];
}
Run Code Online (Sandbox Code Playgroud)

所有适配器的代码都是这样的

public class RelationsFragmentsAdapter extends FragmentPagerAdapter {

private final String titles[] = new String[3];
private final Fragment frags[] = new Fragment[titles.length];

public RelationsFragmentsAdapter(FragmentManager fm) {
    super(fm);
    frags[0] = new FriendsFragment();
    frags[1] = new FriendsRequestFragment();
    frags[2] = new FriendsDeclinedFragment();

    Resources resources = AppController.getAppContext().getResources();

    titles[0] = resources.getString(R.string.my_friends);
    titles[1] = resources.getString(R.string.my_new_friends);
    titles[2] = resources.getString(R.string.followers);
}

@Override
public CharSequence getPageTitle(int position) {
    return titles[position];
}

@Override
public Fragment getItem(int position) {
    return frags[position];
}

@Override
public int getCount() {
    return frags.length;
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    frags[position] = (Fragment) super.instantiateItem(container, position);
    return frags[position];
}
Run Code Online (Sandbox Code Playgroud)

}