Android FragmentStatePagerAdapter,如何标记片段以便以后查找

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12384971/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 10:30:59  来源:igfitidea点击:

Android FragmentStatePagerAdapter, how to tag a fragment to find it later

androidandroid-viewpager

提问by Héctor Júdez Sapena

When using the FragmentStatePageAdapterI get the fragments like this:

使用时FragmentStatePageAdapter我得到这样的片段:

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

However, later on my code I need to find this fragment to set a property. In some other parts of the app where I use fragments I basically tag them and look for them using findFragmentByTag(TAG)but with now I don't know how to do it.

但是,稍后在我的代码中,我需要找到此片段来设置属性。在我使用片段的应用程序的其他一些部分中,我基本上标记它们并使用它们寻找它们,findFragmentByTag(TAG)但现在我不知道该怎么做。

How do can I find the fragments using the FragmentStatePageAdapter?

如何使用 找到片段FragmentStatePageAdapter

回答by Frank

* EDIT *

* 编辑 *

As @ElliotM pointed out, there is a better solution. No need to change anything in your adapter, just get the fragment with:

正如@ElliotM 指出的那样,有一个更好的解决方案。无需更改适配器中的任何内容,只需获取片段:

Fragment myFragment = (Fragment) adapter.instantiateItem(viewPager, viewPager.getCurrentItem());

* OLD SOLUTION *

* 旧解决方案 *

Best option is the second solution here: http://tamsler.blogspot.nl/2011/11/android-viewpager-and-fragments-part-ii.html

最好的选择是这里的第二个解决方案:http: //tamsler.blogspot.nl/2011/11/android-viewpager-and-fragments-part-ii.html

In short: you keep track of all the "active" fragment pages. In this case, you keep track of the fragment pages in the FragmentStatePagerAdapter, which is used by the ViewPager..

简而言之:您跟踪所有“活动”片段页面。在这种情况下,您可以跟踪 ViewPager 使用的 FragmentStatePagerAdapter 中的片段页面。

public Fragment getItem(int index) {
    Fragment myFragment = MyFragment.newInstance();
    mPageReferenceMap.put(index, myFragment);
    return myFragment;
}

To avoid keeping a reference to "inactive" fragment pages, we need to implement the FragmentStatePagerAdapter's destroyItem(...) method:

为了避免保留对“非活动”片段页面的引用,我们需要实现 FragmentStatePagerAdapter 的 destroyItem(...) 方法:

public void destroyItem(View container, int position, Object object) {
    super.destroyItem(container, position, object);
    mPageReferenceMap.remove(position);
}

... and when you need to access the currently visible page, you then call:

...当您需要访问当前可见的页面时,您可以调用:

int index = mViewPager.getCurrentItem();
MyAdapter adapter = ((MyAdapter)mViewPager.getAdapter());
MyFragment fragment = adapter.getFragment(index);

... where the MyAdapter's getFragment(int) method looks like this:

...其中 MyAdapter 的 getFragment(int) 方法如下所示:

public MyFragment getFragment(int key) {
    return mPageReferenceMap.get(key);
}

--- EDIT:

- - 编辑:

Also add this in your adapter, for after an orientation change:

还要在您的适配器中添加它,以便在方向更改后:

/**
 * After an orientation change, the fragments are saved in the adapter, and
 * I don't want to double save them: I will retrieve them and put them in my
 * list again here.
 */
@Override
public Object instantiateItem(ViewGroup container, int position) {
    MyFragment fragment = (MyFragment) super.instantiateItem(container,
            position);
    mPageReferenceMap.put(position, fragment);
    return fragment;
}

回答by Lancelot

I've found another way of doing it, not sure if there would be any issues for using it, it seems ok to me.

我找到了另一种方法,不确定使用它是否会有任何问题,对我来说似乎没问题。

I was checking at the code for FragmentStatePageAdapterand I saw this method:

我正在检查FragmentStatePageAdapter的代码,我看到了这个方法:

@Override
52     public Object More ...instantiateItem(View container, int position) {
53         // If we already have this item instantiated, there is nothing
54         // to do.  This can happen when we are restoring the entire pager
55         // from its saved state, where the fragment manager has already
56         // taken care of restoring the fragments we previously had instantiated.
57         if (mFragments.size() > position) {
58             Fragment f = mFragments.get(position);
59             if (f != null) {
60                 return f;
61             }
62         }
63 
64         if (mCurTransaction == null) {
65             mCurTransaction = mFragmentManager.beginTransaction();
66         }
67 
68         Fragment fragment = getItem(position);
69         if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
70         if (mSavedState.size() > position) {
71             Fragment.SavedState fss = mSavedState.get(position);
72             if (fss != null) {
73                 fragment.setInitialSavedState(fss);
74             }
75         }
76         while (mFragments.size() <= position) {
77             mFragments.add(null);
78         }
79         fragment.setMenuVisibility(false);
80         mFragments.set(position, fragment);
81         mCurTransaction.add(container.getId(), fragment);
82 
83         return fragment;
84     }

You can use this method to get the fragment already instated for that particular position. So if you want to get Fragment at position 1, you just need to call:

您可以使用此方法获取已为该特定位置设置的片段。因此,如果您想在位置 1 处获取 Fragment,您只需要调用:

myFragmentStatePageAdpater.instantiateItem(null, 1)

Hope that helps

希望有帮助

回答by Chris Lacy

I implemented this by adding a getItemTag(int position)function to FragmentStatePagerAdapter. A drop-in version of the updated file is hereif anyone else wants to go this route.

我加入了实现此getItemTag(int position)发挥作用FragmentStatePagerAdapter。如果其他人想走这条路,这里有更新文件的插入版本。

回答by Alexey

Solution with storing fragments to a HashMap in your getItem() method does not work if your activity is re-created!

如果重新创建您的活动,将片段存储到您的 getItem() 方法中的 HashMap 的解决方案不起作用!

Problem is, default implementation of the FragmentStatePagerAdapter restores fragments directly from the FragmentManager without calling the getItem() method. This means that you'll never get a chance to store a reference to your fragment.

问题是, FragmentStatePagerAdapter 的默认实现直接从 FragmentManager 恢复片段,而不调用 getItem() 方法。这意味着您将永远没有机会存储对片段的引用。

For more info, see source code: FragmentStatePagerAdapter#restoreState.

有关详细信息,请参阅源代码: FragmentStatePagerAdapter#restoreState

This basically means that the only way to get a reference to your fragment is by resorting to reflections. This is relatively* safe** in case youre using support library.

这基本上意味着获得片段引用的唯一方法是诉诸反射。如果您使用支持库,这相对*安全**。

Here's how:

就是这样:

    @SuppressWarnings("unchecked")
    public Fragment getFragment(int position) {
        try {
            Field f = FragmentStatePagerAdapter.class.getDeclaredField("mFragments");
            f.setAccessible(true);
            ArrayList<Fragment> fragments = (ArrayList<Fragment>) f.get(this);
            if (fragments.size() > position) {
                return fragments.get(position);
            }
            return null;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

relatively* means that its not as dangerous as using reflection on framework classes. Support classes are compiled into your app and there is no way that this code will work on your device but will crash on some other device. You can still potentially break this solution by updating support library to a newer version

相对* 意味着它不像在框架类上使用反射那么危险。支持类被编译到您的应用程序中,此代码无法在您的设备上运行,但在其他设备上会崩溃。您仍然可以通过将支持库更新到较新版本来破坏此解决方案

safe** its never really safe to use reflections; however you have to resort to this method when a library you're using has design flaws.

安全** 使用反射从来都不是真正安全的;但是,当您使用的库存在设计缺陷时,您必须采用这种方法。

回答by Arvis

As @Lancelot mentioned, You may just call and cast result to your SuperCoolFragment:

正如@Lancelot 提到的,您可以调用并将结果转换为您的 SuperCoolFragment:

SuperCoolFragment frag = (SuperCoolFragment) yourFragmentStatePageAdpater.instantiateItem(null, position); 

回答by Guang

Override setPrimaryItem, and using that position, it would be the right page index:

Override setPrimaryItem,并使用该位置,它将是正确的页面索引:

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
        super.setPrimaryItem(container,position,object);
        if (position == 1) {
            currentPageIndex=cameraFragment.pageIndex;
}

回答by Ivan V

I tried Frank's answer that suggests Second Approach from the tutorial linked in it, bot for some reason after adding method getFragment() to my ViewPagerAdapter I can't access it via mViewPager.getAdapter.getFragment() as if it doesn't exist, so I moved mPageReferenceMap declaration from the ViewPagerAdapter to the enclosing class so it is easily accessed from any point of the enclosing class (in my case it is MainActivity's callback method from other fragment) which finally makes it possible to pass data between fragments. Thanks to Frank and feel free to implement my fixture if you like me face issue with accessing custom getFragment method.

我尝试了弗兰克的答案,该答案建议从其中链接的教程中使用第二种方法,在将方法 getFragment() 添加到我的 ViewPagerAdapter 后,由于某种原因,我无法通过 mViewPager.getAdapter 访问它。getFragment() 就好像它不存在一样,所以我将 mPageReferenceMap 声明从 ViewPagerAdapter 移动到封闭类,以便从封闭类的任何点轻松访问它(在我的情况下,它是来自其他片段的 MainActivity 的回调方法),最后使得在片段之间传递数据成为可能。感谢 Frank,如果您喜欢我在访问自定义 getFragment 方法时遇到问题,请随时实现我的装置。

回答by Romain Piel

Another solution is to copy paste the source code of FragmentStatePagerAdapterand add a getFragmentmethod:

另一种解决方法是复制粘贴FragmentStatePagerAdapter的源代码并添加一个getFragment方法:

public Fragment getFragment(int position) {
    if (position >= mFragments.size()) {
        return null;
    }
    return mFragments.get(position);
}

回答by Hang Guan

Create a holder to hold the new SuperCoolFragment object. Then tag and return the holder object.

创建一个持有者来保存新的 SuperCoolFragment 对象。然后标记并返回持有者对象。

@Override
public Fragment getItem(int position) {
    SuperCoolFragment superCoolFragment = new SuperCoolFragment();
    superCoolFragment.setTag(YOUR_TAG);
    return superCoolFragment;
}