Android ViewPager + 带有动态 ListViews 的片段

Posted

技术标签:

【中文标题】Android ViewPager + 带有动态 ListViews 的片段【英文标题】:Android ViewPager + Fragments with dynamic ListViews 【发布时间】:2015-02-12 23:19:45 【问题描述】:

在我的应用中,我有标签活动(比如说 10 个标签)。每个标签页都包含FragmentListView(此ListView 中显示的数据是从我的服务器动态加载的)。我使用ViewPager来显示这些页面。我不想将所有Fragments 都保留在内存中,所以我决定使用FragmentStatePagerAdapter(我的适配器类扩展了这些类)。

    假设选择了第三个选项卡。然后,例如,当我转到第一个选项卡时,应该从头开始创建此选项卡的 Fragment(这很好,这就是 FragmentStatePagerAdapter 的工作方式)但 无需 恢复此片段的先前状态(例如,ListView 不应滚动到上次访问此 Fragment 时保存的位置 - 现在已滚动)。 所以我的第一个问题是:我怎样才能实现这样的行为?换句话说,我希望我的适配器在从头开始创建时不要恢复Fragmentstate。

    再一次,假设选择了第三个选项卡。然后,例如,当我转到第二个选项卡时,Fragmentfor 这个选项卡应该仍在内存中(这很好,这就是 FragmentStatePagerAdapter 的工作方式),但在这种情况下,我想决定我的 ListViewdata 是否应该更新(取决于某些条件)。如何通知Fragment 它已被选中?

【问题讨论】:

【参考方案1】:

对于 #1,请查看 this 博客文章。他们谈论修复 FragmentStatePagerAdpater 以处理索引的片段类发生变化的情况,这并不是您想要的。但是,它详细显示了状态是如何保存/恢复的,您应该能够从那里弄清楚如何防止它。

对于#2,在包含 ViewPager 的 Fragment 中实现 OnPageChangeListener。然后使用this 在当前片段发生变化时获取它,以便您可以在其上调用一些公共方法,告诉它更新。

【讨论】:

在您发布答案之前,这正是我所做的。我使用FragmentStatePagerAdapter 代码实现了我自己的PagerAdapter,没有状态保存/恢复部分。它对我的第二个问题也很有用,因为现在,在我自己的适配器中,我可以轻松访问当前的Fragment(因为有内部Fragments 列表 - 不需要额外的映射/数组)。我只是害怕我的想法是正确的,但你的答案完全一样,所以我现在确定。非常感谢。【参考方案2】:

我希望我的适配器在创建时不要恢复 Fragmentstate 从头开始。

将以下代码添加到FragmentStatePagerAdapter

@Override
public int getItemPosition(Object object)
    return PagerAdapter.POSITION_NONE;

如何通知此 Fragment 它已被选中?

当您在fragmentStatePagerAdaptergetItem 中加载每个fragment 时,还使用getInstance(链接的示例很好)设计模式将位置传递给片段。在onPageSelected(int position) 中调用LocalBroadcastManager 并将位置作为额外的。在每个片段中检查意图,如果额外中的位置与片段中存储的位置相同,这意味着用户选择了该片段,因此在onReceive 方法中更新列表。

【讨论】:

1.我已经测试了您的解决方案,但它不起作用,我已经检查了原因。根据 ViewPager 源代码,当调用 mAdaper.getItemPosition(someObject) 后,它返回 POSITION_NONEFragment 因为此页面被销毁(适配器在销毁之前保存Fragment 状态),但它仍然不能阻止FragmentStatePagerAdapter重新创建时恢复Fragments 状态。更重要的是,它似乎效率低下,因为每次调用 notifyDataSetChanged() 时,所有 Fragments 都会被销毁并重新创建。 2. 没关系,但我选择了更简单的解决方案。【参考方案3】:

对于#1,AFAIK,当转到第一个选项卡时,与该选项卡的 Fragment 相关联将再次创建,就像您使用 FragmentStatePagerAdapter 时它永远不会访问一样。现在你说 ListView 是滚动的,你确定你使用的是 FragmentStatePagerAdapter??

另一方面,如果您使用FragmentPagerAdapter,它将从 FragmentManager 中分离所有关闭的 Fragment,但将它们保留在内存中,这就是为什么当您直接从第三个选项卡返回到第一个选项卡时,您会看到 ListView 停留最后状态。你提到的行为让我觉得你似乎在使用 FragmentPagerAdapter 而不是 FragmentStatePagerAdapter。

如果你确认是FragmentStatePagerAdapter,我相信如果你不手动恢复状态(即使用Fragment中的onSaveInstanceState()方法),回来的Fragment肯定会恢复到刚出生的样子。

对于#2,如果您想在 Fragment 完全可见时执行某些操作,您可以覆盖 setUserVisibleHint 方法以将您的代码放在那里。

public class YourFragement extend android.support.v4.app.Fragment 
    ...
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) 
        super.setUserVisibleHint(isVisibleToUser);
        if (conditions satisfied) 
            // do your job
        
    
    ...

【讨论】:

FragmentPagerAdapterFragmentStatePagerAdapter 具有相同的可见语义——唯一的区别是前者保留了Fragment 对象本身,而后者只保留了它们的状态。分离和销毁 Fragment 都会导致其 Views 被销毁,重新附加 Fragment 与创建具有相同保存状态的新 Fragment 具有相同的语义。 @corsair992 是的,你说得对,我很注意源代码终于找到FragmentManager破坏Fragment的地方,PagerAdater没有参与这个机制。感谢您的提醒,并为我的错误向大家道歉。

以上是关于Android ViewPager + 带有动态 ListViews 的片段的主要内容,如果未能解决你的问题,请参考以下文章

带有viewpager2 android的导航图

android viewpager如何动态添加页面?

带有底点的 Android ViewPager

如何使用 viewpager(android) 创建动态选项卡?

在android中使用viewpager的带有多个片段的SearchView

Android基础控件——ViewPager实现带有动画的引导页