web-dev-qa-db-ja.com

FragmentPagerAdapterに戻る->フラグメントが空

バックスタックに追加され、表示されるフラグメント(pagerFragmentと呼びます)があります。 viewPagerFragmentPagerAdapterを保持します。 FragmentPagerAdapterには、AとBの2つのフラグメントが保持されています(たとえば、)。

最初にフラグメントを追加するとうまくいきます。

フラグメントAには、一度クリックするとフラグメント(C)をバックスタックに追加するボタンがあります。

問題はこれです。そのフラグメント(C)を追加してからクリックすると、pagerAdapterが空になり、内部にフラグメントが表示されません。

ハックを使用し、pagerFragments onDestroyView()の子フラグメント(AおよびB)を破棄すると、問題が解決しますが、このハックを使用したくありません。

問題が何であるか考えていますか?

58
Amit Ishai

私も同じ問題を抱えていました。私にとっての解決策は簡単でした:

私が持っていたonCreateViewで:

// Create the adapter that will return a fragment for each of the three
// primary sections of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(getActivity()
    .getSupportFragmentManager());

ここで、SectionPageAdapterは次のようなものです。

class SectionsPagerAdapter extends FragmentPagerAdapter {
...
}

getSupportFragmentManagerをに変更した後

mSectionsPagerAdapter = new SectionsPagerAdapter(getChildFragmentManager());

それは働き始めました!お役に立てれば。

85
Mike Mitterer

ViewPagerがPagerFragment内にあるため、ネストされたフラグメントを使用しているようです。 FragmentPagerAdapterのコンストラクターにgetChildFragmentManager()を渡しましたか?そうでない場合。

FragmentStatePagerAdapterは必要ないと思いますが、Fragment状態の保存と復元を処理するので、試してみます。 onDestroyView()ハックが機能するという事実により、FragmentStatePagerAdapterが必要になる場合があります。

また、FragmentPagerAdapterがFragmentsを追加する方法と関係がある場合もあります。 FragmentPagerAdapterはフラグメントをバックスタックに追加しません。 ViewPagerに10ページ以上が追加されていて、ユーザーがページをスワイプした場合を想像してみてください。ユーザーは、アプリから戻るためだけに11回反撃する必要があります。

また、この投稿に関連している可能性があります: ネストされたフラグメントとバックスタック

また、フラグメントCを何に追加するのかわかりません。 ViewPagerと同じコンテナーに追加していますか?

少なくとも、調査するいくつかのオプションがあります。これらの状況では、Android SDKソースコードにデバッグして、動作の原因を確認します。 AOSPソース を取得し、フレームワーク/サポートとフレームワークを追加することをお勧めします/ baseをSDKソースとして使用するこれは、何が起こっているのかを理解し、問題が発生するまでランダムな変更を行わないようにするための唯一の真の方法です。

私もこのプロジェクトで問題に直面しました。根本的な原因はFragmentPagerAdapterが機能する方法です。

FragmentPagerAdapterは、現在必要としないFragmentをビューから切り離すだけで、FragmentManagerからは削除しません。彼は再度フラグメントを表示したい場合、ViewPagerのビューIDとアダプターのgetItemId(position)呼び出しによって返されたIDから作成されたタグを使用してFragmentManagerにフラグメントがまだ含まれているかどうかを調べます。彼がフラグメントを見つけた場合、彼はFragmentManagerの更新トランザクション内でそのビューへのフラグメントのアタッチをスケジュールするだけです。この方法でFragmentが見つからない場合のみ、アダプターのgetItem(position)呼び出しを使用して新しいフラグメントを作成します。

FragmentPagerAdapterを持つViewPagerを含むFragmentの問題は、含まれているFragmentがバックスタックに置かれたときに、FragmentManagerのコンテンツがクリーンアップされないことです。含まれているフラグメントがバックスタックから戻った場合、新しいビューが作成されますが、FragmentManagerには古いビューにアタッチされていたフラグメントがまだ含まれており、既存のフラグメントのアタッチは機能しなくなります。

この問題を取り除く最も簡単な方法は、ネストされたフラグメントを回避することです。 :)

2番目に簡単な方法は、他の投稿で既に述べたように、FragmentPagerAdapterのChildFragmentManagerを使用する方法です。これは、コンテナフラグメントのライフサイクル中に適切に更新されるためです。

現在のプロジェクトのように両方のオプションが不可能なプロジェクトがあるため、サブフラグメントのhashCodeをその位置のフラグメントのアイテムIDとして使用することにより、任意のFragmentManagerで機能するソリューションをここに公開しました。アダプター内のすべての位置のすべてのフラグメントを保管するという代償が伴います。

public class MyPagerAdapter extends FragmentPagerAdapter {

private static int COUNT = ...;
private final FragmentManager fragmentManager;
private Fragment[] subFragments = new Fragment[COUNT];
private FragmentTransaction cleanupTransaction;

public MyPagerAdapter(FragmentManager fragmentManager) {
    super(fragmentManager);
    this.fragmentManager = fragmentManager;
}

@Override
public Fragment getItem(int position) {
    return getSubFragmentAtPosition(position);
}

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

@Override
public long getItemId(int position) {
    return getSubFragmentAtPosition(position).hashCode();
}

//The next three methods are needed to remove fragments no longer used from the fragment manager
@Override
public void startUpdate(ViewGroup container) {
    super.startUpdate(container);
    cleanupTransaction = fragmentManager.beginTransaction();
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);
    cleanupTransaction.remove((Fragment) object);
}

@Override
public void finishUpdate(ViewGroup container) {
    super.finishUpdate(container);
    cleanupTransaction.commit();
}

private Fragment getSubFragmentAtPosition(int position){
    if (subFragments[position] == null){
        subFragments[position] = ...;
    }
    return subFragments[position];
}

}

1
Nantoka

getChildFragmentManager()の代わりにgetSupportFragmentManager()を使用してください。正常に動作します。

0
vijay rathore

同じ問題が発生しましたアダプタを一度に2度設定するだけです。

コード例:

private fun displayImg(photo1:String, photo2:String){
    val pager:ViewPager = v?.findViewById(R.id.ProductImgPager)!!
    val arr = ArrayList<String>()
    arr.add(photo1)
    arr.add(photo2)
    pager.adapter = AdapterImageView(fm, arr ,arr.size)
    pager.adapter = AdapterImageView(fm, arr ,arr.size)

}
0
Biplob Das