Android ViewPager + 带有动态 ListViews 的片段
Posted
技术标签:
【中文标题】Android ViewPager + 带有动态 ListViews 的片段【英文标题】:Android ViewPager + Fragments with dynamic ListViews 【发布时间】:2015-02-12 23:19:45 【问题描述】:在我的应用中,我有标签活动(比如说 10 个标签)。每个标签页都包含Fragment
和ListView
(此ListView 中显示的数据是从我的服务器动态加载的)。我使用ViewPager
来显示这些页面。我不想将所有Fragments
都保留在内存中,所以我决定使用FragmentStatePagerAdapter
(我的适配器类扩展了这些类)。
假设选择了第三个选项卡。然后,例如,当我转到第一个选项卡时,应该从头开始创建此选项卡的 Fragment
(这很好,这就是 FragmentStatePagerAdapter
的工作方式)但 无需 恢复此片段的先前状态(例如,ListView
不应滚动到上次访问此 Fragment
时保存的位置 - 现在已滚动)。
所以我的第一个问题是:我怎样才能实现这样的行为?换句话说,我希望我的适配器在从头开始创建时不要恢复Fragment
state。
再一次,假设选择了第三个选项卡。然后,例如,当我转到第二个选项卡时,Fragment
for 这个选项卡应该仍在内存中(这很好,这就是 FragmentStatePagerAdapter
的工作方式),但在这种情况下,我想决定我的 ListView
data 是否应该更新(取决于某些条件)。如何通知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 它已被选中?
当您在fragmentStatePagerAdapter
的getItem
中加载每个fragment
时,还使用getInstance(链接的示例很好)设计模式将位置传递给片段。在onPageSelected(int position) 中调用LocalBroadcastManager 并将位置作为额外的。在每个片段中检查意图,如果额外中的位置与片段中存储的位置相同,这意味着用户选择了该片段,因此在onReceive
方法中更新列表。
【讨论】:
1.我已经测试了您的解决方案,但它不起作用,我已经检查了原因。根据 ViewPager 源代码,当调用mAdaper.getItemPosition(someObject)
后,它返回 POSITION_NONE
,Fragment
因为此页面被销毁(适配器在销毁之前保存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
...
【讨论】:
FragmentPagerAdapter
和FragmentStatePagerAdapter
具有相同的可见语义——唯一的区别是前者保留了Fragment
对象本身,而后者只保留了它们的状态。分离和销毁 Fragment
都会导致其 View
s 被销毁,重新附加 Fragment
与创建具有相同保存状态的新 Fragment
具有相同的语义。
@corsair992 是的,你说得对,我很注意源代码终于找到FragmentManager
破坏Fragment的地方,PagerAdater没有参与这个机制。感谢您的提醒,并为我的错误向大家道歉。以上是关于Android ViewPager + 带有动态 ListViews 的片段的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 viewpager(android) 创建动态选项卡?