How to get existing fragments when using FragmentP

2019-01-01 12:24发布

I have problem making my fragments communicating with each other through the Activity, which is using the FragmentPagerAdapter, as a helper class that implements the management of tabs and all details of connecting a ViewPager with associated TabHost. I have implemented FragmentPagerAdapter just as same as it is provided by the Android sample project Support4Demos.

The main question is how can I get particular fragment from FragmentManager when I don't have neither Id or Tag? FragmentPagerAdapter is creating the fragments and auto generating the Id and Tags.

14条回答
闭嘴吧你
2楼-- · 2019-01-01 12:58

I always use this base class, when I need to access child fragments or primary (currently visible) fragment. It doesn't rely on any implementation details and it takes care for lifecycle changes, because overwritten methods get called in both cases - when a new fragment instance created and when instance gets received from FragmentManager.

public abstract class FragmentPagerAdapterExt extends FragmentPagerAdapter {

    private final ArrayList<Fragment> mFragments;
    private Fragment mPrimaryFragment;

    public FragmentPagerAdapterExt(FragmentManager fm) {
        super(fm);
        mFragments = new ArrayList<>(getCount());
    }

    @Override public Object instantiateItem(ViewGroup container, int position) {
        Object object = super.instantiateItem(container, position);
        mFragments.add((Fragment) object);
        return object;
    }

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

    @Override public void setPrimaryItem(ViewGroup container, int position, Object object) {
        super.setPrimaryItem(container, position, object);
        mPrimaryFragment = (Fragment) object;
    }

    /** Returns currently visible (primary) fragment */
    public Fragment getPrimaryFragment() {
        return mPrimaryFragment;
    }

    /** Returned list can contain null-values for not created fragments */
    public List<Fragment> getFragments() {
        return Collections.unmodifiableList(mFragments);
    }
}
查看更多
浮光初槿花落
3楼-- · 2019-01-01 13:00

Just go on try this code,

public class MYFragmentPAdp extends FragmentPagerAdapter {

    public MYFragmentPAdp(FragmentManager fm) {
        super(fm);
    }

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

     @Override
     public Fragment getItem(int position) {
         if (position == 0)
             Fragment fragment = new Fragment1();
         else (position == 1)
             Fragment fragment = new Fragment2();
         return fragment;
     }
}
查看更多
余欢
4楼-- · 2019-01-01 13:01

I have found answer on my question based on following post: reusing fragments in a fragmentpageradapter

Few things I have learned:

  1. getItem(int position) in the FragmentPagerAdapter is rather misleading name of what this method actually does. It creates new fragments, not returning existing ones. In so meaning, the method should be renamed to something like createItem(int position) in the Android SDK. So this method does not help us getting fragments.
  2. Based on explanation in the post support FragmentPagerAdapterholds reference to old fragments you should leave the creation of the fragments to the FragmentPagerAdapter and in so meaning you have no reference to the Fragments or their tags. If you have fragment tag though, you can easily retrieve reference to it from the FragmentManager by calling findFragmentByTag(). We need a way to find out tag of a fragment at given page position.

Solution

Add following helper method in your class to retrieve fragment tag and send it to the findFragmentByTag() method.

private String getFragmentTag(int viewPagerId, int fragmentPosition)
{
     return "android:switcher:" + viewPagerId + ":" + fragmentPosition;
}

NOTE! This is identical method that FragmentPagerAdapter use when creating new fragments. See this link http://code.google.com/p/openintents/source/browse/trunk/compatibility/AndroidSupportV2/src/android/support/v2/app/FragmentPagerAdapter.java#104

查看更多
一个人的天荒地老
5楼-- · 2019-01-01 13:02

The way I did it is define an Hashtable of WeakReferences as follows:

protected Hashtable<Integer, WeakReference<Fragment>> fragmentReferences;

Then I wrote the getItem() method like this:

@Override
public Fragment getItem(int position) {

    Fragment fragment;
    switch(position) {
    case 0:
        fragment = new MyFirstFragmentClass();
        break;

    default:
        fragment = new MyOtherFragmentClass();
        break;
    }

    fragmentReferences.put(position, new WeakReference<Fragment>(fragment));

    return fragment;
}

Then you can write a method:

public Fragment getFragment(int fragmentId) {
    WeakReference<Fragment> ref = fragmentReferences.get(fragmentId);
    return ref == null ? null : ref.get();
}

This seems to work well and I find it a little less hacky than the

"android:switcher:" + viewId + ":" + position

trick, as it does not rely on how the FragmentPagerAdapter is implemented. Of course if the fragment has been released by the FragmentPagerAdapter or if it has not been yet created, getFragment will return null.

If anybody finds something wrong with this approach, comments are more than welcome.

查看更多
何处买醉
6楼-- · 2019-01-01 13:07

The main road block with getting a handle to the fragments is you can not rely on getItem(). After an orientation change, references to the fragments will be null and getItem() is not called again.

Here's an approach that does not rely upon the implementation of FragmentPagerAdapter to get the tag. Override instantiateItem() which will return the fragment created from getItem() or found from the fragment manager.

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Object value =  super.instantiateItem(container, position);

    if (position == 0) {
        someFragment = (SomeFragment) value;
    } else if (position == 1) {
        anotherFragment = (AnotherFragment) value;
    }

    return value;
}
查看更多
美炸的是我
7楼-- · 2019-01-01 13:07

See this post on returning fragments from the FragmentPagerAdapter. Does rely on you knowing the index of your fragment - but this would be set in getItem() (at instantiation only)

查看更多
登录 后发表回答