我有一个片段(我称之为pagerFragment
),它被添加到后台并且可见。它包含viewPager
和FragmentPagerAdapter
。 FragmentPagerAdapter
拥有(比方说)两个片段:A和B.
首先添加片段效果很好。
片段A有一个按钮,一旦点击,就会在后台堆叠中添加一个片段(C)。
问题是:如果我添加该片段(C),然后单击返回,pagerAdapter
为空,我看不到任何片段。
如果我使用hack,并在pagerFragment
s onDestroyView()
中销毁子片段(A和B),这就解决了问题,尽管我不想使用这个hack
任何想法可能是什么问题?
答案 0 :(得分:83)
我遇到了同样的问题。对我来说解决方案很简单:
在onCreateView中我有:
// Create the adapter that will return a fragment for each of the three
// primary sections of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(getActivity()
.getSupportFragmentManager());
其中SectionPageAdapter是这样的:
class SectionsPagerAdapter extends FragmentPagerAdapter {
...
}
将getSupportFragmentManager更改为后
mSectionsPagerAdapter = new SectionsPagerAdapter(getChildFragmentManager());
它开始工作了!
希望这会有所帮助。
答案 1 :(得分:13)
听起来您正在使用嵌套片段,因为您的ViewPager在PagerFragment中。您是否已将getChildFragmentManager()传递给FragmentPagerAdapter的构造函数?如果没有,你应该。
我认为你不需要FragmentStatePagerAdapter,但我会给它一个镜头,因为它处理保存和恢复Fragment状态。你的onDestroyView()hack工作的事实让我觉得你可能想要一个FragmentStatePagerAdapter。
它也可能与FragmentPagerAdapter添加片段的方式有关。 FragmentPagerAdapter不会将片段添加到Backstack。想象一下,如果您的ViewPager中添加了10多个页面,并且用户可以浏览它们。用户需要回击11次才能退出应用程序。
它也可能与这篇文章有关:Nested Fragments and The Back Stack。
此外,我不确定你要将片段C添加到。您是否将其添加到与ViewPager相同的容器中?
至少你有几个选择可以调查。在这些情况下,我喜欢调试Android SDK源代码,看看是什么导致了这种行为。我建议抓取AOSP source并添加框架/支持和框架/ base作为SDK源。这是理解正在发生的事情的唯一真实方式,并避免在事情发生之前进行随机更改。
答案 2 :(得分:1)
我刚刚在项目中遇到了问题。根本原因是FragmentPagerAdapter的工作方式:
FragmentPagerAdapter只是从它的View中分离出一个他当前不需要的片段,但是不会从FragmentManager中删除它。当他想再次显示片段时,他会查看FragmentManager是否仍然包含使用从ViewPager的视图ID创建的标记和由适配器getItemId(position)调用返回的id的片段。如果他找到一个Fragment,他只是在FragmentManager的更新事务中安排Fragment附加到它的View。只有当他没有以这种方式找到片段时,他才使用适配器getItem(position)调用创建一个新片段!
包含带有FragmentPagerAdapter的ViewPager的Fragment的问题是,当包含Fragment放入后端堆栈时,FragmentManager的内容永远不会被清除。如果包含Fragment从后向堆栈返回,则会创建一个新视图,但FragmentManager仍然包含附加到旧视图的片段,并且现有片段的附加不再起作用。
解决此问题的最简单方法是避免嵌套片段。 :)
第二种最简单的方法就像在其他帖子中已经提到的那样,使用ChildFragmentManager作为FragmentPagerAdapter,因为这个在容器片段的生命周期中得到了适当的更新。
由于有两个选项都不可能的项目(作为我当前的项目),我在这里发布了一个解决方案,通过使用子片段的hashCode作为该位置片段的项目ID,可以使用任意FragmentManager 。它的代价是存储适配器中所有位置的所有片段。
public class MyPagerAdapter extends FragmentPagerAdapter {
private static int COUNT = ...;
private final FragmentManager fragmentManager;
private Fragment[] subFragments = new Fragment[COUNT];
private FragmentTransaction cleanupTransaction;
public MyPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
this.fragmentManager = fragmentManager;
}
@Override
public Fragment getItem(int position) {
return getSubFragmentAtPosition(position);
}
@Override
public int getCount() {
return COUNT;
}
@Override
public long getItemId(int position) {
return getSubFragmentAtPosition(position).hashCode();
}
//The next three methods are needed to remove fragments no longer used from the fragment manager
@Override
public void startUpdate(ViewGroup container) {
super.startUpdate(container);
cleanupTransaction = fragmentManager.beginTransaction();
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
cleanupTransaction.remove((Fragment) object);
}
@Override
public void finishUpdate(ViewGroup container) {
super.finishUpdate(container);
cleanupTransaction.commit();
}
private Fragment getSubFragmentAtPosition(int position){
if (subFragments[position] == null){
subFragments[position] = ...;
}
return subFragments[position];
}
}
答案 3 :(得分:0)
使用getChildFragmentManager()
代替getSupportFragmentManager()
。
它会工作正常。
答案 4 :(得分:0)
我遇到了同样的问题,只需一次设置适配器两次即可。
示例代码:
private fun displayImg(photo1:String, photo2:String){ val pager:ViewPager = v?.findViewById(R.id.ProductImgPager)!! val arr = ArrayList<String>() arr.add(photo1) arr.add(photo2) pager.adapter = AdapterImageView(fm, arr ,arr.size) pager.adapter = AdapterImageView(fm, arr ,arr.size) }