当前位置: 首页 > 知识库问答 >
问题:

如何在使用FragmentPagerAdapter时获取现有片段

莫兴言
2023-03-14

我无法通过活动使我的片段相互通信,该活动使用fragmentPagerAdapter作为一个帮助器类,该类实现对选项卡的管理以及将viewpager与相关联的tabhost连接的所有细节。我已经实现了FragmentPagerAdapter,就像Android示例项目Support4Demos提供的一样。

主要的问题是,当我既没有Id也没有标记时,如何从fragmentManager获得特定的片段?FragmentPagerAdapter创建片段并自动生成Id和标记。

共有1个答案

魏元白
2023-03-14

注意:在这个答案中,我将引用fragmentPagerAdapter及其源代码。但是一般的解决方案也应该应用于FragmentStatePagerAdapter

如果您正在阅读本文,您可能已经知道FragmentPagerAdapter/FragmentStatePagerAdapter旨在为ViewPager创建片段,但是在活动重新创建时(无论是从设备旋转还是系统关闭应用程序以重新获得内存),这些片段将不会再次创建,而是从FragmentManager检索它们的实例。现在,假设您的活动需要获取对这些片段的引用,以便对它们进行操作。对于这些创建的片段,您没有ID标记,因为fragmentPagerAdapter在内部设置它们。所以问题是如何在没有这些信息的情况下获得对它们的引用...

我所见过的关于这个问题和类似问题的许多解决方案都依赖于通过调用fragmentmanager.findfragmentbytag()和模仿内部创建的标记来获取对现有片段的引用:“Android:switcher:”+viewId+“:”+id。这样做的问题是,您依赖于内部源代码,我们都知道,这些源代码不能保证永远保持不变。Google的Android工程师可以很容易地决定更改标记结构,这将破坏您的代码,使您无法找到对现有片段的引用。

下面是一个简单的示例,说明如何获取对fragmentPagerAdapter返回的fragment的引用,该引用不依赖于在fragment上设置的内部fragment标记。关键是重写instantiateitem()并将引用保存在there,而不是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();
        }
    }
}

或者,如果您更喜欢使用标记而不是类成员变量/对片段的引用,您也可以以相同的方式获取由fragmentPagerAdapter设置的标记:注意:这不适用于fragmentStatePagerAdapter,因为它在创建片段时不设置标记

@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;
}

请注意,此方法不依赖于模仿FragmentPagerAdapter设置的内部标记,而是使用适当的API来检索它们。这样,即使标记SupportLibrary的未来版本中发生更改,您仍然是安全的。

不要忘记,根据活动的设计,您试图处理的片段可能还存在,也可能还不存在,因此在使用引用之前,您必须通过执行null检查来说明这一点。

另外,如果您使用的是FragmentStatePagerAdapter,那么您就不想保留对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...
}

 类似资料:
  • 我使用带有ViewPager的FragmentPagerAdapter来切换片段 那么我如何使片段调用它们的onResume()呢?

  • 我在使用FragmentPagerAdapter时遇到问题。我想从视图寻呼机中的片段中检索数据。当我调用getItem()方法时,它返回一个片段,但不创建片段。所有片段变量均为null。我需要做什么来实例化片段?这是我的适配器。 这是viewpager中的片段。 我不太了解ViewPager是如何工作的,但据我所知,片段在没有设置任何变量的情况下返回的原因是因为ViewPager没有附加片段。如何

  • 问题内容: 如何使用PIL或任何其他Python库获取图片边的大小? 问题答案: 根据文档。

  • 我是android开发的新手,我正在使用JSON解析方法解析我的数据,我用List Fragment扩展了我的类,我希望我的数据在列表视图中,但问题是除了图像之外,我得到的所有数据都很完美,我不知道如何解算,我的回答如下

  • 问题内容: 我正在尝试收集一个部门中的ID列表(数组) 给我一个jQuery对象,但不是一个真正的数组; 我可以 然后使用for循环将id属性放入另一个数组 或者我可以做 无论如何,我只是想看看jQuery中是否有速记来做到这一点。 问题答案: //但是我无法真正获取ID并将其分配给不在范围内的数组?(或者我可以) 是的你可以! 请注意,当您处于正确的轨道上时,Sighohwell和cletus都

  • 我正在尝试通过将数据与接口传递给片段来将数据从对话片段获取到片段。到目前为止,我知道首先是因为它的片段,我需要在MainActive上实现接口,并从那里将数据发送到我想要的任何片段。我明白,但我不知道如何做到这一点。到目前为止,我已经在MainActive中实现了接口,我正在获取数据,但我不知道如何将其发送到片段。 主要活动 对话片段-此对话片段从画廊/相机获取图片 片段-此片段应从dialogf