web-dev-qa-db-ja.com

再開時にViewPagerのフラグメントビューが復元されない

ActionBarタブを設定しています。 4つのタブで構成されています。 TabbedFragmentから離れて戻ってくるまでは、すべて問題ありません。

私はこのようなタブを作成します:

  @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final ActionBar actionBar = getActionBar();

        tabs = Lists.newArrayList();
        tabs.add(new TabDefinition<>("Tab 1"));
        tabs.add(new TabDefinition<>("Tab 2"));
        tabs.add(new TabDefinition<>("Tab 3"));
        tabs.add(new TabDefinition<>("Tab 4"));


        for (TabDefinition tab : tabs) {
            actionBar.addTab(actionBar.newTab()
                .setText(tab.text)
                .setTag(tab.tag)
                .setTabListener(this));
        }
    }

そして、このようにアダプターを初期化します:

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

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    viewPager = (ViewPager) view.findViewById(R.id.pager);

    viewPager.setAdapter(new FragmentStatePagerAdapter(getFragmentManager()) {

        @Override
        public Fragment getItem(int position) {
            return tabs.get(position).fragment;
        }

        @Override
        public int getCount() {
            return tabs.size();
        }
    });

    viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
        @Override
        public void onPageSelected(int position) {
            getActionBar().setSelectedNavigationItem(position);
        }
    });

    viewPager.setCurrentItem(getActionBar().getSelectedNavigationIndex(), true);
}

TabbedFragmentに戻ると、選択したタブとその隣の1にはコンテンツがありません。空のビュー。しかし、現在+ 2を選択すると、フラグメントコンテンツが読み込まれます。その後、最初のフラグメントコンテンツに戻ります。
たとえば、A、B、C、Dのタブがあります。 TabbedFragmentを離れる前に、タブAを選択しました。TabbedFragmentに戻ると、タブAにいますが、空です。タブBも同様です。
しかし、タブCを選択すると、それが作成されてロードされます。タブAに戻り、再作成されます。

ここで何が問題になるのでしょうか?

33
Martynas Jurkus

しばらくして再び同じ問題に遭遇したので、この質問を更新しました。 FragmentStatePagerAdapterを使用している場合は、getChildFragmentManager()ではなくgetFragmentManager()を使用してFragmentManagerを提供する必要があります。参照 問題55068:バックスタックを介して戻るナビゲーション時にViewPagerが子フラグメントを更新しない

65
Martynas Jurkus

さて、FragmentStatePagerAdapterを使用すると、上記のようにデフォルトでoffScreenPageLimitがデフォルトで1に設定されているため、複数のフラグメントを離れると、フラグメントが破棄されます。

通常、このクラスは、非常に大きなFragmentsのセットがあるアクティビティ、つまり大量のビューをスクロールする必要があるアクティビティに使用されます。アプリケーションで必要なのが3〜4個のタブだけである場合は、代わりにFragmentPagerAdapterを使用して、offScreenPageLimitを3のように指定することをお勧めします。したがって、4番目のタブに到達すると、それ以前の3つのタブはすべてそのままになります。記憶にある。

これは、私が作成したgithub上のプロジェクトのサンプルコードで、このoffScreenPageLimitを追加したくない場合にフラグメントを動的にロードする方法を示しています。

https://github.com/lt-tibs1984/InterfaceDemo/blob/master/src/com/divshark/interfacedemo/InterfaceDemoMain.Java

このクラスのすべてのコードをウォークスルーすると、ViewPagerがスライドされるたびに、フラグメントを動的にロードする方法がわかります。最も注目すべきは下部です。

このコードをダウンロードして、目的のテストベースとして使用できます。 viewPagerのonCreate()メソッドにsetOffScreenPageLimit(2)を追加してみて、異なる動作に注目してください。動作を確認するには、フラグメント1のテキストを編集します。この設定の有無にかかわらず、[離れる]に移動して戻ってください。フラグメントが再作成されることはないため、設定されると、フラグメントのテキストは変更後のテキストのままになります。

質問がある場合は、追加で質問してください。

幸運を

[〜#〜]更新[〜#〜]

private static final String [] fragmentClasses = {"com.example.project.YourFragment1","com.example.project.YourFragment2","com.example.project.YourFragment3"};



 viewPager.setAdapter(new FragmentStatePagerAdapter(getFragmentManager()) {

    @Override
    public Fragment getItem(int position) {

       Fragment fragmentAtPosition = null;

       // $$$$ This is the Important Part $$$$$
       // Check to make sure that your array is not null, size is greater than 0 , current position is greater than equal to 0, and position is less than length
       if((fragmentClasses != null) && (fragmentClasses.length > 0)&&(position >= 0)&& (position < fragmentClasses.length))
        {
       // Instantiate the Fragment at the current position of the Adapter
        fragmentAtPosition = Fragment.instantiate(getBaseContext(), fragmentClasses[position]);
        fragmentAtPosition.setRetainInstance(true);

       }

        return fragmentAtPosition;
    }

    @Override
    public int getCount() {
        return fragmentClasses.length;
    }
});
3
kandroidj

タブとして使用するフラグメントに問題があると思います。再開しても何も表示されないようです( フラグメントライフサイクル を参照)。現在選択されている+/- 1タブのみが空である「奇妙な」問題は、offScreenPageLimitの-​​ ViewPager がデフォルトで1であるためです。このしきい値を超えるすべてのタブが再作成されます。

したがって、値を増やすと(場合によっては)、再開後にすべてのタブが空に表示されます。レイアウトの拡張、アダプタの設定などに使用するライフサイクルメソッドをFragmentコードにチェックインします。これが問題の原因です。

1
saschoar

これは、フラグメントのロード中にAndroidが現在とcurrent + 1をロードするため、デバッグすると、すぐ次のフラグメントに対してonPauseが呼び出されないことが原因と考えられます。

TabHost.OnTabChangeListenerのonTabChanged()メソッドでプログラムでコンテンツを再ロードできます。

1
techieWings

多くの研究を行った後、これは私のために働いた。フラグメントに3つのタブがあり、他のフラグメントに切り替えられる複雑なレイアウトがあります。ホームボタンを押しても、ViewpagerAdapterは状態を保持することに気づきました。私の問題は、前後に切り替えると、子フラグメントのUIビュー要素が無効になり、クラッシュすることでした。重要なのは、あなたのnewViewPagerAdapter出さないことです。アダプターのnullチェックを追加するとうまくいきました。また、必要に応じてsetOffscreenPageLimit()を割り当ててください。また、私が理解していることから、setRetainInstance(true);はUIを持つフラグメントには使用しないでください。ヘッドレスフラグメント用に設計されています。

タブを保持するフラグメントで:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_tab, container, false);
    tabLayout = (TabLayout) view.findViewById(R.id.tablayout);
    viewPager = (ViewPager) view.findViewById(R.id.viewPager);

    //Important!!! Do not fire the existing adapter!!
    if (viewPagerAdapter == null) {
        viewPagerAdapter = new ViewPagerAdapter(getChildFragmentManager());
        viewPagerAdapter.addFragments(new AFragment(), "A");
        viewPagerAdapter.addFragments(new BFragment(), "B");
        viewPagerAdapter.addFragments(new CFragment(), "C");
    }
    //Allocate retention buffers for three tabs, mandatory
    viewPager.setOffscreenPageLimit(3);
    tabLayout.setupWithViewPager(viewPager);
    viewPager.setAdapter(viewPagerAdapter);

    return view;
}
0
Len

または、より簡単にtabbedfragmentに戻るとき(インテントを使用し、フラグメントがアクティビティ内にあると想定)、以下を使用します。

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

これにより、元のアクティビティが保持され、再作成されるのではなくスタックの一番上に移動されるため、viewPagerを再作成する必要はありません。

0