7

アクティビティに直接接続されたビューで ViewPager と一緒に FragmentPagerAdapter を使用していた Android コードでリファクタリングを行いました。その後、FragmentPageAdapter は、リファクタリングの一環として、Activity から別の Fragment (現在はその Activity の子) に移動されました。

この変更はうまくいきませんでした。たとえば、向きを変更すると、キャッシュされたタブが消えます。NullPointerExceptions は、Fragment サブクラスのいたるところにスローされます。これは、findViewById がビュー コンポーネントを見つけることができないためです (回転の変更後に、フラグメントのビュー階層が何らかの形で破棄されたように見えます)。

Android Support Library の最新バージョンを使用しています。

何がうまくいかなかったのですか?

編集:

私の現在の実装:

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();
    }

ViewPager はフラグメントに存在するため、フラグメントを作成するgetChildFragmentManger()代わりに、によって返される FragmentManager を使用する必要があります。getActivity().getFragmentManager()

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);

のレイアウトにある場合GridViewは、からアクセスしてください。FragmentgetView().findViewById...

于 2013-03-04T08:55:13.190 に答える