7

我在一些 Android 代码中做了一些重构,我在直接连接到 Activity 的视图中使用 FragmentPagerAdapter 和 ViewPager。作为重构的一部分,FragmentPageAdapter 然后从 Activity 移动到一个单独的 Fragment(现在是该 Activity 的子项)。

这种变化并不顺利。例如,在方向更改后,缓存的选项卡会消失。NullPointerExceptions 在我的 Fragment 子类中随处可见,因为 findViewById 无法找到它的视图组件(看起来片段的视图层次结构在旋转更改后以某种方式被破坏)。

我正在使用最新版本的 Android 支持库。

关于出了什么问题的任何想法?

编辑:

我目前的实现:

public class TabsPageAdapter extends FragmentPagerAdapter {

    ...

    @Override
    public Fragment getItem(int index) {
        // tabs = list of Fragment instances created in contructor of pager adapter - bad habbit?
        return tabs.get(index).getTabFragment();
    }

    ...

}


public class StatsFragment extends Fragment {

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

        TabsPageAdapter adapter = new TabsPageAdapter(getActivity().getSupportFragmentManager(), getActivity());
        ViewPager viewPager = (ViewPager) root.findViewById(R.id.tabPager);
        viewPager.setAdapter(adapter);
        viewPager.setOffscreenPageLimit(3);
        TabPageIndicator pageIndicator = (TabPageIndicator) root.findViewById(R.id.tabIndicator);
        pageIndicator.setViewPager(viewPager);  
        return root;
    }
}


public class MedalsTab extends Fragment {

    private MedalAdapter adapter;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.medals, container, false);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState){
        super.onActivityCreated(savedInstanceState);
        this.adapter = new MedalAdapter();
        GridView gridView = (GridView) getActivity().findViewById(R.id.grdMedals);
        // Nullpointerexception is thrown here
        gridView.setAdapter(adapter);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        //first saving my state, so the bundle wont be empty.
        //http://code.google.com/p/android/issues/detail?id=19917
        outState.putString("WORKAROUND_FOR_BUG_19917_KEY", "WORKAROUND_FOR_BUG_19917_VALUE");
        super.onSaveInstanceState(outState);
    }

    ...

}

在浏览寻呼机适配器中的选项卡时,我也遇到了这个异常。

E/AndroidRuntime(28706): java.lang.NullPointerException
E/AndroidRuntime(28706):    at android.support.v4.app.Fragment.instantiate(Fragment.java:391)
4

2 回答 2

12

这是我解决问题的方法:

我更改了 getItem 方法来构造并返回一个新实例(感谢 Luksprog):

    @Override
    public Fragment getItem(int index) {
        return tabs.get(index).constructFragment();
    }

我们需要使用返回的 FragmentManagergetChildFragmentManger()而不是getActivity().getFragmentManager()创建片段,因为 ViewPager 驻留在片段中:

TabsPageAdapter adapter = new TabsPageAdapter(getChildFragmentManager(), getActivity());
于 2013-03-06T00:06:45.373 回答
4

// tabs = 在寻呼机适配器的构造器中创建的 Fragment 实例列表 - 坏习惯?

是的,这很糟糕,可能是轮换后问题的根源。当需要在页面中显示片段时,ViewPager将使用该方法获取片段。getItem轮换后,ViewPager将检查其状态并查看之前有多少片段,并在没有该getItem方法的情况下手动恢复它们。如果您在此机制之外保存片段,您要么需要更改适配器,使其仅使用列表中的片段(getItem()还不够),要么更新片段列表以仅引用由ViewPager. 您很可能不这样做,并且在轮换之后您尝试访问列表片段,假设它们是来自ViewPager, 的动作,它将抛出NullPointerException.

GridView gridView = (GridView) getActivity().findViewById(R.id.grdMedals);

如果那GridViewFragment的布局中,请通过 访问它getView().findViewById...

于 2013-03-04T08:55:13.190 回答