使用FragmentPagerAdapter的ViewPager中的片段在第二次查看时为空白


98

我有一个片段界面,其底部带有选项卡,可在主视图中打开不同的片段。

我有一个特定的片段,它是项目列表。如果用户选择此列表中的一个项目,则会打开另一个片段,其中包含一个viewpager,该viewpager会在上一个片段的列表中的所有项目之间水平滚动。这很好。

viewpager使用FragmentPagerAdapter来显示项目。

当用户在列表中选择一个项目,查看它,然后单击选项卡栏上的按钮以返回到列表,然后选择另一个项目时,就会出现问题。第二次选择项目时,出现空白屏幕,而不是viewpager。发生这种情况时,我在LogCat中没有收到任何错误。

为什么viewpager只第一次出现?

FragmentPagerAdapter:

public class ViewPagerAdapter extends FragmentPagerAdapter {
    Cursor mCursor;

    public ViewPagerAdapter(FragmentManager fm, Cursor c) {
        super(fm);
        mCursor = c;
    }

    public void changeCursor(Cursor c) {
        mCursor = c;
        this.notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        if (mCursor == null) return 0;
        else return mCursor.getCount();
    }

    @Override
    public Fragment getItem(int position) {
        mCursor.moveToPosition(position);
        return TeamCardFragment.newInstance(mCursor, position);
    }
}

PagerFragment:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);

    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);

    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();

    return mView;
}

private class setAdapterTask extends AsyncTask<Void, Void, Void> {
    protected Void doInBackground(Void... params) {
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        mViewPager.setAdapter(mAdapter);
        mViewPager.setCurrentItem(mCursorPosition);
    }
}

Answers:


221

我遇到过同样的问题。将PageAdapter的父类从更改android.support.v4.app.FragmentPagerAdapterandroid.support.v4.app.FragmentStatePagerAdapter解决ViewPager“第二次”的显示问题!


2
不开玩笑吗?我没有此代码了,否则我将对其进行测试。也许这个答案会帮助别人。
howettl 2011年

10
多好的人啊!我一直在寻找这种解决方案好几天了!感谢一个吨的男人,像魅力一样工作。但是我内心的开发者在问这种改变会产生什么影响?我的意思是为什么它以前不起作用以及为什么在StatePagerAdapter中
Anand Sainath 2013年

1
另外,您还需要@Override public int getItemPosition(对象对象){return POSITION_NONE; }
Helin Wang

1
也为我工作。这是一个链接。似乎保存了片段状态,这一切都与众不同。developer.android.com/reference/android/support/v4/app/...
Tjaart

1
这是一个偶然的巧合,正确的答案是@Daniel F的答案。总之,为了方便起见,这里的评论者之间的差异FragmentPagerAdapter,并FragmentStatePagerAdapter在前者更为适合几页,它保留了所有内存中的片段因此具有页面切换上最好的表演,而后者更适合于很多页面,它会破坏片段,仅保留其状态,内存效率更高,但页面切换速度稍慢。
Cristina De Rito

87

我设法通过更换来解决这个getFragmentManager()getChildFragmentManager()父片段。此父片段实例化了android.support.v4.app.FragmentPagerAdapter,以包含可分页(可滑动)的片段,这需要在构造函数中使用片段管理器。我将此构造函数的返回值传递给此构造函数getChildFragmentManager()

hackbod的链接是关键(https://developer.android.com/about/versions/android-4.2.html#NestedFragments),该链接在本文的Fragments中找到

要嵌套片段,只需调用getChildFragmentManager()要在其中添加片段的片段。这将返回一个FragmentManager,您可以像通常在顶级活动中那样使用FragmentManager来创建片段事务。


谢谢...我遇到了类似的问题,试图在包含片段fragmentradapter的onresume()之后重新实例化滑动选项卡视图...我使用的教程来自2016年,我仍然需要将其更改为fragmentstatepageradapter才能获取工作。希望我知道为什么。
Nerdy Bunz's

这个答案节省了我很多时间。因为仅使用FragmentStatePagerAdapter不能解决此处提出的问题。以及FragmentStatePagerAdapter父片段中YourAdapter adapter = new YourAdapter (getChildFragmentManager()); 都必须添加
MMK,

17

对我来说,我不得不在viewpager上调用它:

myViewPager.setSaveFromParentEnabled(false);

我遇到的问题是,viewpager不能刷新,而我所看到的只是空白的空白屏幕,片段应该在该屏幕上。我传入了getChildFragmentManager,但没有帮助。


1
为什么在世界上这项工作呢?这解决了我的问题,但是我不知道为什么。
ClayHerendeen

我现在从代码中删除了它。片段管理器引起了该问题。尝试在getchildfragmentmanager和getfragmentmanager之间切换
j2emanue'1

我已经尝试过了。我已将每个具有嵌套的Tab的ViewPagers禁用了滑动。我知道这是糟糕的设计,但客户不希望我这样做。我正在使用childFragmentManager作为顶层选项卡。切换较低级别的标签栏/ viewpager似乎无法解决该问题。我想我现在会坚持使用setSaveFromParentEnabled(false),因为它正在工作。
ClayHerendeen

您是否在使用最新的支持库
j2emanue

2
最近两天来我遇到了同样的问题。.您的解决方案对我有用。谢谢 !
brijexecon '18

11

在我非常特殊的情况下,当我将CoordinatorLayout与AppBarLayout和ViewPager一起使用时,为我解决的问题是从AppBarLayout xml属性中删除了android:fitsSystemWindows =“ true”

不要问我为什么。我知道这听起来有点荒谬,并且应该没有任何关联,但是由于我已经在适配器中使用了getChildFragmentManager(),所以这条线是唯一引起麻烦的事情。我花了一整天的时间调试我的代码,只是为了找到它,所以希望它可以节省其他人的时间。


3
噢,天哪……我几乎要投降了。你让我抓狂!Google Geez,WTF的AppBarLayout错误吗?我看了将近一百页,花了很多小时进行调试,试图解决这个问题而没有运气。我终于通过您的评论解决了这个问题,我真的很感激。非常感谢!PS:我是如此绝望,我甚至创造了AOSP一个问题:code.google.com/p/android/issues/... XD
纪莲罗卡

感谢您的提示。至少它帮助我们解决了问题。现在,我们正在尝试找出使其全屏显示的选项
Paresh Mayani,

你是救星!我绝对不知道为什么遇到这个问题,但仍然不知道为什么它起作用!
nandu

10

我有一个相同的问题,我将适配器从 FragmentPagerAdapterFragmentStatePagerAdapter并将getFragmentManager()父片段更改为getChildFragmentManager()

其背后的原因FragmentStatePagerAdapter有助于存储大量页面,并且与访问的每个页面关联的内存较少,因为它仅保留片段的已保存状态,而页面不可见。这减少了在片段之间切换时的开销。




1

通过将视图分页器项重新实现为标准视图而不是片段,并相应地更改了适配器,我们解决了这一问题。


您可以尝试删除isViewFromObject(View view,Object object)函数
Mina Samy

有一种更好的方法....://尽管我越深入研究Android,我就会意识到它越不成熟。
StackOverflowed 2012年

1
不支持嵌套片段,因此用标准视图重新实现似乎是个好方法。
西尔夫(Sylphe)2012年

我正在努力解决类似的问题。我尝试使用PagerAdapter而不是FragmentAdapter仍然遇到相同的问题。请帮帮我!
Gaurav Arora

:如果你想使用嵌套的片段,你可以使用这个答案提供的适配器我stackoverflow.com/questions/7700226/...
Slickelito

1

我在Xamarin Android 上第二次出现空白屏幕时遇到了同样的问题。

viewPager.SaveFromParentEnabled = false;

0

您还可以初始化适配器,以在最小化应用程序并随后调用该应用程序时遇到此错误。

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);
    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);
    initViewPagerAdapter();
    return mView;
}
private void initViewPagerAdapter(){
    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();
}

@Override
public void onResume(){
    super.onResume();
    initViewPagerAdapter();
}

0

我有同样的事情,第二次调用寻呼机适配器时,子视图返回NullPointerException。并在FragmentStatePagerAdapter中更改适配器也解决了我的问题。


0

更改FragmentPagerAdapterFragmentStatePagerAdapter 使用getChildFragmentManager()代替getFragmentManager()

getChildFragmentManager()-因为根据文档,它将返回一个私有的FragmentManager,用于在此Fragment中放置和管理Fragment。同时getFragmentManager()将返回FragmentManager与与此活动关联的片段进行交互


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.