フラグメントをページングするビューページャーがあります。私のFragmentPagerAdapter
サブクラスはgetItem
メソッドで新しいフラグメントを作成しますが、これは無駄だと思われます。 FragmentPagerAdapter
のconvertView
と同等のlistAdapter
がありますか?作成済みのフラグメントを再利用できますか?私のコードは以下です。
public class ProfilePagerAdapter extends FragmentPagerAdapter {
ArrayList<Profile> mProfiles = new ArrayList<Profile>();
public ProfilePagerAdapter(FragmentManager fm) {
super(fm);
}
/**
* Adding a new profile object created a new page in the pager this adapter is set to.
* @param profile
*/
public void addProfile(Profile profile){
mProfiles.add(profile);
}
@Override
public int getCount() {
return mProfiles.size();
}
@Override
public Fragment getItem(int position) {
return new ProfileFragment(mProfiles.get(position));
}
}
FragmentPagerAdapter
はすでにFragments
をキャッシュしています。各フラグメントにはタグが割り当てられ、FragmentPagerAdapter
はfindFragmentByTag
の呼び出しを試みます。 getItem
からの結果がfindFragmentByTag
である場合にのみ、null
を呼び出します。したがって、フラグメントを自分でキャッシュする必要はありません。
Geoffの投稿の付録:
findFragmentByTag()
を使用して、Fragment
のFragmentPagerAdapter
への参照を取得できます。タグの名前は次の方法で生成されます。
private static String makeFragmentName(int viewId, int index)
{
return "Android:switcher:" + viewId + ":" + index;
}
viewIdはViewPagerのIDです
このリンクを見てください: http://code.google.com/p/openintents/source/browse/trunk/compatibility/AndroidSupportV2/src/Android/support/v2/app/FragmentPagerAdapter.Java#104 =
この質問を見ている多くの人々が、Fragments
/FragmentPagerAdapter
によって作成されたFragmentStatePagerAdapter
を参照する方法を探しているようです。 internally created tags
に依存せずにこれに対する私のソリューションを提供したいと思います。
ボーナスとして、このメソッドはFragmentStatePagerAdapter
でも機能するはずです。詳細については、以下の注を参照してください。
私がこれまで見た多くの解決策と同様の質問は、FragmentManager.findFragmentByTag()
を呼び出し、 internally created tag:"Android:switcher:" + viewId + ":" + id
を呼び出すことで、既存のFragment
への参照を取得することに依存しています。 。これに関する問題は、内部ソースコードに依存していることです。これは、誰もが知っているように、永遠に同じままであるとは限りません。 GoogleのAndroidエンジニアは、既存のtag
への参照を見つけることができないコードを壊すFragments
構造を変更することを簡単に決定できます。
tag
に依存しない代替ソリューション以下は、Fragments
に設定された内部FragmentPagerAdapter
に依存しないtags
によって返されるFragments
への参照を取得する方法の簡単な例です。重要なのは、 instantiateItem()
をオーバーライドし、そこに参照を保存することですinstead of in getItem()
。
public class SomeActivity extends Activity {
private FragmentA m1stFragment;
private FragmentB m2ndFragment;
// other code in your Activity...
private class CustomPagerAdapter extends FragmentPagerAdapter {
// other code in your custom FragmentPagerAdapter...
public CustomPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
// Do NOT try to save references to the Fragments in getItem(),
// because getItem() is not always called. If the Fragment
// was already created then it will be retrieved from the FragmentManger
// and not here (i.e. getItem() won't be called again).
switch (position) {
case 0:
return new FragmentA();
case 1:
return new FragmentB();
default:
// This should never happen. Always account for each position above
return null;
}
}
// Here we can finally safely save a reference to the created
// Fragment, no matter where it came from (either getItem() or
// FragmentManger). Simply save the returned Fragment from
// super.instantiateItem() into an appropriate reference depending
// on the ViewPager position.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// save the appropriate reference depending on position
switch (position) {
case 0:
m1stFragment = (FragmentA) createdFragment;
break;
case 1:
m2ndFragment = (FragmentB) createdFragment;
break;
}
return createdFragment;
}
}
public void someMethod() {
// do work on the referenced Fragments, but first check if they
// even exist yet, otherwise you'll get an NPE.
if (m1stFragment != null) {
// m1stFragment.doWork();
}
if (m2ndFragment != null) {
// m2ndFragment.doSomeWorkToo();
}
}
}
or クラスメンバー変数/ tags
への参照の代わりにFragments
を使用する場合は、tags
によって設定されたFragmentPagerAdapter
も同じ方法で取得できます。注:これは適用されませんFragmentStatePagerAdapter
を作成するときにtags
を設定しないため、Fragments
に。
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// get the tags set by FragmentPagerAdapter
switch (position) {
case 0:
String firstTag = createdFragment.getTag();
break;
case 1:
String secondTag = createdFragment.getTag();
break;
}
// ... save the tags somewhere so you can reference them later
return createdFragment;
}
このメソッドは、tag
によって設定される内部FragmentPagerAdapter
の模倣に依存せず、代わりにそれらを取得するために適切なAPIを使用することに注意してください。このようにすると、tag
の将来のバージョンでSupportLibrary
が変更されても、安全です。
忘れないでくださいあなたのActivity
の設計に応じて、あなたがしようとしているFragments
はまだ存在しているかもしれないし、そうでないかもしれないので、null
を実行することでそれを説明する必要があります参照を使用する前にチェックします。
また、代わりにでFragmentStatePagerAdapter
を使用している場合は、Fragments
へのハード参照を保持したくない場合があります。メモリ。代わりに、標準の変数ではなくFragment
変数にWeakReference
参照を保存します。このような:
WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment);
// ...and access them like so
Fragment firstFragment = m1stFragment.get();
if (firstFragment != null) {
// reference hasn't been cleared yet; do work...
}
フラグメントがまだメモリ内にある場合、この関数を使用して見つけることができます。
public Fragment findFragmentByPosition(int position) {
FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter();
return getSupportFragmentManager().findFragmentByTag(
"Android:switcher:" + getViewPager().getId() + ":"
+ fragmentPagerAdapter.getItemId(position));
}
v4サポートAPIのサンプルコード
これは(理論的には)質問に対する答えではなく、別のアプローチであることを知っています。
表示されているフラグメントを更新する必要がある問題がありました。私が試みたもの、失敗したもの、そして惨めに失敗したもの...
さまざまなことを試した後、最終的にBroadCastReceiver
を使用してこれを完了しました。目に見えるフラグメントで何かをする必要があるときに、単にブロードキャストを送信して、フラグメントにキャプチャします。
何らかの応答も必要な場合は、ブロードキャストで送信することもできます。
乾杯
将来の読者のために!
ビューページャーでフラグメントを再利用することを考えている場合、最良の解決策は ViewPager 2 を使用することです。これはView Pager 2がRecyclerViewを使用するためです。