Android FragmentPagerAdapterとFragmentStatePagerAdapterの違い

5869 ワード

多くのappのメインインタフェースは下部のいくつかのボタンで、それから切り替えをクリックして異なるUIの表示を表示します.これはView pager+fragmentを使って実現することができますが、注意しないと問題があります.
例えばFragmentPagerAdapterを使用する場合、viewpagerがsetCurrentItem(index)を設定している場合.まずindex-1,index+1およびindexに対応するFragmentのviewをロードし、index=0ならfragmentのviewを2つだけロードする.viewpagerがそのインタフェースにスライドすると、そのfragmentのviewがロードされます.例えば、最初から4番目にスライドし、4番目から1番目にスライドします.このとき、4番目のviewは回収されます.viewはnullです.これは、fragmentのviewが繰り返されることを意味します.これまでのFragmentのonDestroyView()ライフサイクルメソッドが実行されるため、viewは回収されます.もしあなたがまたviewpagerのスライドリスニングをしてviewを通じてどんな業務をするのはN ullPointerExceptionの異常を招きやすいならば、私の前のプロジェクトは出会ったことがあって、繰り返しviewをロードする問題はどのように解決しますか?
第一に、viewpagerのキャッシュをfragmentの個数に設定します.
viewpager.setOffscreenPageLimit(fragmentの個数);
これらの現象は、ロゴを打つことで自分で分析することができます.
FragmentStatePagerAdapaterを使用している場合、viewpagerがスライドするとfragmentがメモリから消去されます.これはソースコードから分析できます.
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    Fragment fragment = (Fragment) object;

    if (mCurTransaction == null) {
        mCurTransaction = mFragmentManager.beginTransaction();
    }
    if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object
            + " v=" + ((Fragment)object).getView());
    while (mSavedState.size() <= position) {
        mSavedState.add(null);
    }
    mSavedState.set(position, fragment.isAdded()
            ? mFragmentManager.saveFragmentInstanceState(fragment) : null);
    mFragments.set(position, null);

    mCurTransaction.remove(fragment);
}

最後の行はFragmentを削除し、FragmentPagerAdapterのソースコード:
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    if (mCurTransaction == null) {
        mCurTransaction = mFragmentManager.beginTransaction();
    }
    if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object
            + " v=" + ((Fragment)object).getView());
    mCurTransaction.detach((Fragment)object);
}

最後の行はFragmentのViewを削除することです.これは両者の大きな違いです.だから、Fragmentが多いときはFragmentStatePagerAdapterを使います.前のFragmentがメモリから削除されるので、メモリを節約します.Fragmentが少ない場合はFragmentPagerAdapterを使います.
もう一つの問題は、動的にFragmentをロードすることです.viewpagerがFragmentを追加または削除することです.これは私のプロジェクトでも遭遇しました.FragmentStatePagerAdapterであれば書き直します.
@Override
public int getItemPosition(Object object) {
    return PagerAdapter.POSITION_NONE;
}

FragmentPagerAdapterなら書き換えます.
@Override
public long getItemId(int position) {
    int hashCode = mFragment.get(position).hashCode();
    return hashCode;
}

viewpagerはviewpagerのようなfragmentを表示することを覚えています.setCurrentItem(0);これを呼び出さないと、現在削除されているfragmentが表示され、スライドするとそのfragmentが消えることに気づきます.