我使用一个ViewPager和一个FragmentStatePagerAdapter来托管三个不同的片段:

(Fragment1) (Fragment2) (Fragment3)

当我想从FragmentActivity中的ViewPager中获取Fragment1时。

问题是什么,我该如何解决它?


当前回答

对于从ViewPager中抓取片段,在这里和其他相关的SO线程/博客上有很多答案。我见过的每个人都很坏,他们通常属于下面列出的两种类型之一。如果你只想抓取当前片段,还有一些其他有效的解决方案,比如这个线程上的其他答案。

如果使用FragmentPagerAdapter参见下面。如果使用FragmentStatePagerAdapter,值得一看。抓取不是FragmentStateAdapter中当前索引的索引并没有那么有用,因为从本质上讲,这些索引将完全被删除,离开视图/ offScreenLimit边界。

不幸的道路

错误:维护自己的内部片段列表,当FragmentPagerAdapter.getItem()被调用时添加

Usually using a SparseArray or Map Not one of the many examples I have seen accounts for lifecycle events so this solution is fragile. As getItem is only called the first time a page is scrolled to (or obtained if your ViewPager.setOffscreenPageLimit(x) > 0) in the ViewPager, if the hosting Activity / Fragment is killed or restarted then the internal SpaseArray will be wiped out when the custom FragmentPagerActivity is recreated, but behind the scenes the ViewPagers internal fragments will be recreated, and getItem will NOT be called for any of the indexes, so the ability to get a fragment from index will be lost forever. You can account for this by saving out and restoring these fragment references via FragmentManager.getFragment() and putFragment but this starts to get messy IMHO.

错误:构造自己的标签id,匹配在FragmentPagerAdapter中使用的内容,并使用它从FragmentManager中检索页面片段

这在处理第一个内部数组解决方案中丢失片段引用的问题上是更好的,但正如上面和网上其他地方的答案中正确指出的那样——它是ViewPager内部的私有方法,可以在任何时间或任何OS版本中更改,这让人感觉很不舒服。

为这个解决方案重新创建的方法是

private static String makeFragmentName(int viewId, long id) {
    return "android:switcher:" + viewId + ":" + id;
}

viewpage . instantiateitem ()

与上面的getItem()类似但不破坏生命周期的方法是钩子到instantiateItem()而不是getItem(),因为前者将在每次创建/访问索引时调用。请看这个答案

快乐之路:构建你自己的FragmentViewPager

从最新支持库的源代码中构造您自己的FragmentViewPager类,并更改用于生成片段标记的内部方法。你可以用下面的替换。这样做的好处是,你知道标签的创建永远不会改变,而且你不依赖于私有api /方法,这总是很危险的。

/**
 * @param containerViewId the ViewPager this adapter is being supplied to
 * @param id pass in getItemId(position) as this is whats used internally in this class
 * @return the tag used for this pages fragment
 */
public static String makeFragmentName(int containerViewId, long id) {
    return "android:switcher:" + containerViewId + ":" + id;
}

然后,正如文档所说,当你想抓取一个片段用于索引只是调用像这样的方法(你可以把自定义FragmentPagerAdapter或一个子类)意识到,如果getItem还没有被调用的页面,即它还没有被创建,结果可能是空的。

/**
 * @return may return null if the fragment has not been instantiated yet for that position - this depends on if the fragment has been viewed
 * yet OR is a sibling covered by {@link android.support.v4.view.ViewPager#setOffscreenPageLimit(int)}. Can use this to call methods on
 * the current positions fragment.
 */
public @Nullable Fragment getFragmentForPosition(int position)
{
    String tag = makeFragmentName(mViewPager.getId(), getItemId(position));
    Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
    return fragment;
}

这是一个简单的解决方案,解决了其他两个解决方案在网络上随处可见的问题

其他回答

我处理它首先使所有片段的列表(list <Fragment> fragments;),我将使用,然后将它们添加到分页器,使其更容易处理当前查看的片段。

So:

@Override
onCreate(){
    //initialise the list of fragments
    fragments = new Vector<Fragment>();

    //fill up the list with out fragments
    fragments.add(Fragment.instantiate(this, MainFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, MenuFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, StoresFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, AboutFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, ContactFragment.class.getName()));


    //Set up the pager
    pager = (ViewPager)findViewById(R.id.pager);
    pager.setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager(), fragments));
    pager.setOffscreenPageLimit(4);
}

那么这个就可以叫做

public Fragment getFragment(ViewPager pager){   
    Fragment theFragment = fragments.get(pager.getCurrentItem());
    return theFragment;
}

然后我可以把它扔进if语句中只有在正确的片段上才会运行

Fragment tempFragment = getFragment();
if(tempFragment == MyFragmentNo2.class){
    MyFragmentNo2 theFrag = (MyFragmentNo2) tempFragment;
    //then you can do whatever with the fragment
    theFrag.costomFunction();
}

但这只是我的hack和slash方法,但它为我工作,我用它做相关的改变,我目前显示的片段,当后退按钮被按下。

这是基于上面Steven的回答。这将返回已经附加到父活动的片段的实际实例。

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
    for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {

        Fragment viewPagerFragment = (Fragment) mViewPager.getAdapter().instantiateItem(mViewPager, i);
        if(viewPagerFragment != null && viewPagerFragment.isAdded()) {

            if (viewPagerFragment instanceof FragmentOne){
                FragmentOne oneFragment = (FragmentOne) viewPagerFragment;
                if (oneFragment != null){
                    oneFragment.update(); // your custom method
                }
            } else if (viewPagerFragment instanceof FragmentTwo){
                FragmentTwo twoFragment = (FragmentTwo) viewPagerFragment;

                if (twoFragment != null){
                    twoFragment.update(); // your custom method
                }
            }
        }
    }

最简单、最简洁的方法。如果你在ViewPager中所有的片段都属于不同的类,你可以像下面这样检索并区分它们:

public class MyActivity extends Activity
{

    @Override
    public void onAttachFragment(Fragment fragment) {
        super.onAttachFragment(fragment);
        if (fragment.getClass() == MyFragment.class) {
            mMyFragment = (MyFragment) fragment;
        }
    }

}

Must将FragmentPagerAdapter扩展到你的ViewPager适配器类。 如果你使用FragmentStatePagerAdapter,那么你将无法通过它的ID找到你的Fragment

public static String makeFragmentName(int viewPagerId, int index) {
  return "android:switcher:" + viewPagerId + ":" + index;
}

如何使用这种方法:-

Fragment mFragment = ((FragmentActivity) getContext()).getSupportFragmentManager().findFragmentByTag(
       AppMethodUtils.makeFragmentName(mViewPager.getId(), i)
);
InterestViewFragment newFragment = (InterestViewFragment) mFragment;

我找不到一个简单干净的方法来做这件事。然而,ViewPager小部件只是另一个ViewGroup,它承载着你的片段。ViewPager将这些片段作为直接子片段。所以你可以遍历它们(使用. getchildcount()和. getchildat()),看看你正在寻找的片段实例当前是否加载到ViewPager中,并获得对它的引用。例如,你可以使用一些静态的唯一ID字段来区分片段。

注意,ViewPager可能没有加载你正在寻找的片段,因为它是一个像ListView一样的虚拟化容器。