FragmentPagerAdapter 带有 ViewPager 和两个 Fragment。从第二个转到第一个并更新第一个的文本

Posted

技术标签:

【中文标题】FragmentPagerAdapter 带有 ViewPager 和两个 Fragment。从第二个转到第一个并更新第一个的文本【英文标题】:FragmentPagerAdapter with ViewPager and two Fragments. Go to the first from the second and update first's text 【发布时间】:2012-04-18 19:32:01 【问题描述】:

我不熟悉FragmentPagerAdapter,所以这将是我们(你)认真阅读描述的问题之一。

结构:我有一个FragmentPagerAdapter(代码如下),它一次可以容纳两个片段。第一个显示书摘,第二个显示书名列表。

目标:我想实现标题中描述的:用户可以导航到分页器中的第二个片段,点击一个标题,然后我想将用户移回第一个片段并告诉第一个片段更新文本。第一个片段有一个triggerRefresh 方法。

代码:我相信我的问题是因为FragmentPagerAdapter 重用/创建片段的方式(我不明白)。这是我的课:

static class MyFragmentPagerAdapter extends FragmentPagerAdapter 

    public MyFragmentPagerAdapter(FragmentManager fm) 
        super(fm);
    

    @Override
    public int getCount() 
        return NUM_ITEMS;
    

    @Override
    public Fragment getItem(int position) 
        switch(position) 
        case 0:
            return new ExcerptsFragment();
        case 1:
            return new BookListFragment();
        default:
            throw new IllegalArgumentException("not this many fragments: " + position);
        
    

这就是我创建相关成员的方式:

ViewPager mViewPager = (ViewPager) findViewById(R.id.pager);
MyFragmentPagerAdapter mFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mFragmentPagerAdapter);

这是我在 Activity 的其他地方尝试过的,当我收到来自书名 Fragment 的回调时,选择了标题:

mViewPager.setCurrentItem(0); // back to excerpts screen page. It's OK.
// Here's the problem! How to identify the fragment 0 
// to ExcerptsFragment and call its triggerRefresh()?!?

系列问题:

调用适配器的getView() 将不起作用,因为它将返回ExcerptsFragment 的新实例,它不是当前附加的实例(如预期的那样,引发异常)。

我在这里看到很多人 (example) 只是将片段存储在 getView() 中。那正确吗?因为通过查看官方示例,对我来说似乎是一种反模式(通过持有项目来击败自动参考)。这也是here 和here 的意见(在我看来是正确的)。

有什么建议吗?如果我一点都不了解这一切,我不会感到惊讶......

【问题讨论】:

【参考方案1】:

免责声明:虽然这对我来说之前效果很好,你应该知道依赖内部私人行为的经典陷阱。虽然我编写的测试最终会在内部实现发生变化时警告我,但我已经转向greener pastures。你也应该这样做。因此,在我看来,这个问题及其答案的价值只是历史性的。


抱歉这个问题,我想是时候了。

为了解决这个问题,我按原样实现了this solution。似乎工作得很好。所以,我相信这只是通过弄清楚它的 Id 是如何命名的来找到(当前附加的)片段实例的问题。上面的链接解释了它是如何制作的。

我选择回答我自己的问题而不是删除它,因为我相信像我这样的寻呼机新手将从“真实案例场景”中受益。我看到的大多数答案都在谈论理论,顺便说一句,这是正确的方法......但没有一个真实的例子可以研究有时像我这样的人会迷路。

无论如何,这是我需要的最后一段代码(上面的注释部分):

int n = 0;
mViewPager.setCurrentItem(n); // in the question I had stopped here.

ExcerptsFragment f = (ExcerptsFragment) ContainerActivity.this
        .getSupportFragmentManager().findFragmentByTag(getFragmentTag(n));
f.triggerRefresh();

// ... below the helper method: used the solution from the link.

private String getFragmentTag(int pos)
    return "android:switcher:"+R.id.pager+":"+pos;

所以,我感觉这是一个强大的解决方案,因为我没有持有任何对片段的引用(因此存在引用过时的风险)。我将自己的代码保持在最低限度,从而最大限度地减少我做蠢事的机会。

当然,如果您有什么要补充、向我们展示、告诉我们这样做的问题或可以改进的地方,我会很高兴收到您的来信。 p>

【讨论】:

您不应依赖与分配标签的内部机制的兼容性。请参阅我对类似问题的回答如何正确执行此操作:***.com/questions/14035090/… @morgwai 谢谢你的警告。我加入了免责声明以警告潜在读者。 不客气 :) 我认为最好直接提供指向我的答案的链接(不仅是那个问题),因为我的答案非常新,因此得分仍然很低,所以读者可能只是坚持 2 个得分最高的答案之一,这两个答案都有问题。 (我在我的回答中添加了一些解释,为什么覆盖 instantiateItem 的解决方案本身可能还不够) 对不起,我必须通过。我从不直接或间接链接或以其他方式认可我(仍然)没有使用、测试或确认的解决方案(如前所述,我已经从答案中的“解决方案”(引用)继续前进了很长一段时间现在)。作为个人评论,我建议您不要担心赞成票和知名度。如果这些年来我在 SO 上注意到的一件事是用户找到最佳答案并为他们投票,如果他们有问题并且解决方案更好,则解决他们的问题。不要担心这个。如果其他答案有问题,让用户自己判断。 ;-) 我并不真正关心我的 UIP(无用的互联网积分),而是关心人们被高分错误答案误导,但无论如何 ;)【参考方案2】:

我自己搜索了一段时间来解决这个问题。您的方法原则上有效,但如果 Android 基类实现中的片段标记创建代码发生更改,它将破坏您的代码。这是一个非常讨厌的依赖!

更优雅的方法是解决问题并在片段中保留一个基本活动实例。在您的活动中为标签实现一个设置器,并在创建时在片段内调用它 - 那里的标签只需使用 getTag() 即可。

可以在here找到一个示例实现。

【讨论】:

迄今为止这个非常随机问题的最佳解决方案。但是有两件事:您可以使用 getActivity() 获得对“父活动”的引用。而且您需要记住,您需要通过配置更改保留标签名称,因为即使可能重新创建适配器,片段也可能不会(因此不会再次设置标签)【参考方案3】:

我通过在创建片段时使用 Wea​​kReferences 解决了这个问题。见:https://***.com/a/23843743/734151

如果您发现此方法有任何问题,请发表评论。

【讨论】:

以上是关于FragmentPagerAdapter 带有 ViewPager 和两个 Fragment。从第二个转到第一个并更新第一个的文本的主要内容,如果未能解决你的问题,请参考以下文章

在Fragment中嵌套使用viewpagerindicator切换Fragment返回后出现空白页与FragmentPagerAdapter页面预加载的解决方案

使用 FragmentPagerAdapter 的 FragmentTransaction

无法更新FragmentPagerAdapter中的片段

为啥我不能从 FragmentPagerAdapter 分离片段?

使用 ViewPager + FragmentPagerAdapter 处理方向更改

ViewPager中的FragmentPagerAdapter,FragmentStatePagerAdapter