【问题标题】:Referencing Fragments inside ViewPager在 ViewPager 中引用片段
【发布时间】:2012-05-13 18:21:39
【问题描述】:

我在 ViewPager 中引用我的片段时遇到问题。我想这样做是因为从我的活动中我想刷新指定位置的片段(例如当前显示的片段)。

目前我有这样的事情:

public static class MyPagerAdapter extends FragmentPagerAdapter {

    private static final String TAG = "MyPagerAdapter";
    private static HashMap<Integer, EventListFragment> mPageReferenceMap = new HashMap<Integer, EventListFragment>();

    public MyPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return NUM_ITEMS;
    }

    @Override
    public Fragment getItem(int position) {
        Log.i(TAG, "getItem: "+position);
        int dateOffset = position-1;
        EventListFragment mFragment = EventListFragment.newInstance(dateOffset);
        mPageReferenceMap.put(position, mFragment);
        return mFragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        Log.i(TAG, "destroyItem: "+position);
        mPageReferenceMap.remove(position);
        super.destroyItem(container, position, object);
    }


    public EventListFragment getFragment(int key) {
        Log.i(TAG, "Size of pager references: "+mPageReferenceMap.size());
        return mPageReferenceMap.get(key);
    }
}

问题是destroyItem()getItem() 更频繁地被调用,所以我留下了空引用。如果我不使用destroyItem() 来清除对已破坏片段的引用……那么我引用了不存在的片段。

有什么好的方法可以引用使用EventListFragment mFragment = EventListFragment.newInstance(dateOffset); 创建的片段吗?或者我应该怎么做才能从我的活动中刷新 ViewPager 中的片段(准确地说是从选项菜单中)?

【问题讨论】:

    标签: android android-fragments


    【解决方案1】:

    我设法解决了。诀窍是在 Activity 中创建参考列表,而不是 PagerAdapter。它是这样的:

    List<WeakReference<EventListFragment>> fragList = new ArrayList<WeakReference<EventListFragment>>();
    
    @Override
    public void onAttachFragment (Fragment fragment) {
        Log.i(TAG, "onAttachFragment: "+fragment);
        if(fragment.getClass()==EventListFragment.class){
            fragList.add(new WeakReference<EventListFragment>((EventListFragment)fragment));
        }
    }
    public EventListFragment getFragmentByPosition(int position) {
    
        EventListFragment ret = null;
        for(WeakReference<EventListFragment> ref : fragList) {
            EventListFragment f = ref.get();
            if(f != null) {
                if(f.getPosition()==position){
                    ret = f;
                }
            } else { //delete from list
                fragList.remove(f);
            }
        }
        return ret;
    
    }
    

    当然,您的片段必须实现 getPosition() 函数,但无论如何我都需要这样的东西,所以这不是问题。

    感谢 Alex Lockwood 对 WeakReference 的建议!

    【讨论】:

    • 我刚刚完成了我的期末考试,并决定回来看看你的工作是否顺利......很高兴我能够提供帮助(即使不是主要问题:P)。
    • 问题:fragList.remove() 调用不应该传递弱引用而不是片段吗?
    • @Michael:我开始使用这样的方法,而且效果很好。但是由于 fragList 包含弱引用,因此这些条目似乎受到垃圾回收的影响,即使您仍然可能需要它们。我已经看到 getFragmentByPosition() 方法有时会返回 null,所以我认为这就是正在发生的事情。任何想法如何解决这个问题?谢谢。
    • @gcl1 我只需要更新内存中的片段。如果一个片段被垃圾收集,那么在它对用户可见之前它会被再次创建,因此无论如何都会更新。所以片段为空对我来说不是问题。为什么需要更新被垃圾回收的片段?
    【解决方案2】:

    两件事:

    1. 在 Activity 的 onCreate 方法(或初始化 ViewPager 的任何位置)中添加以下行:

      mPager.setOffscreenPageLimit(NUM_ITEMS-1);
      

      这会将额外的屏幕外页面保留在内存中(即防止它们被破坏),即使它们当前没有显示在屏幕上。

    2. 您可能会考虑实现您的HashMap,以便它拥有WeakReference&lt;Fragment&gt;s 而不是Fragments 本身。请注意,这需要您更改 getFragment 方法,如下所示:

      WeakReference<Fragment> weakRef = mPageReferenceMap.get(position);
      return (weakRef != null) ? weakRef.get() : null;
      

      这与您的问题无关......这只是我注意到并认为我会引起您注意的事情。将WeakReferences 保存到您的Fragments 将允许您利用垃圾收集器为您确定可达性的能力,因此您不必自己做。

    【讨论】:

    • 至于 2. => 它不能解决我的问题,但可能是防止泄漏的好主意,谢谢。还有 1. => 我会有 7 页,将来可能会更多,可以同时将它们全部保存在内存中吗?
    • 嗯...很明显,您在内存中保留的Fragments 越少越好。如果您想从您的Activity 中按需访问您的Fragments(而不实际切换到Fragments 页面)而不将它们全部保存在内存中,那么修复将是一个棘手的问题。它可能需要深入研究ViewPager 源代码并查看它如何处理Fragment 生命周期。我不知道有什么方法可以做到这一点,但是当我有更多时间时,我会研究一下。
    • 我谦虚地建议,如果您需要在屏幕外的片段中获取任何东西,也许您不应该将其提供给片段。考虑将其放入 Service 或 ContentProvider 中,并让您的 Fragment 成为它的客户端。
    • 我现在无法访问我的电脑,但我明天也会查看它。感谢您的帮助:-) 只是一个想法-也许有可能将包含特定位置的刷新请求发送到 viewpager 中的所有片段,而应该更新的片段会发现该请求是针对它的?
    • 这绝对是“可能的”,但就像我之前说的,它似乎实现起来会很复杂。在这种情况下,Sparky 的建议似乎是可行的方法,因为它避免了您在屏幕外 Fragments 的生命周期中可能遇到的复杂情况。与其要求重新创建Fragment(或强制Fragment 留在内存中,正如我最初的帖子所建议的那样),Sparky 建议您提供一种更外部的方式来访问Fragment 的状态。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-17
    相关资源
    最近更新 更多