onPageSelected在onCreateView之前运行吗?

3
我正在使用ViewPager循环切换一组片段,并且我希望在每个片段滑动到屏幕上后更新它。基本上,我希望文本在片段稳定后“淡入”。
我尝试使用片段的onStart和onResume方法,虽然这对大多数页面有效,但对于第二个页面却无效,因为由于某些愚蠢的原因,第一页和第二页的onStart/onResume方法会同时调用(在第二页到达屏幕之前)。
现在我正在尝试使用onPageChangeListener的onPageSelected回调来使其工作。该方法如下:
@Override
public void onPageSelected(final int position) {
    mCurrentPosition = position;

    PageFragment fragment = (PageFragment) ((MainActivity.ScreenSlidePagerAdapter) mViewPager.getAdapter()).getItem(position);

    fragment.onSelect();

}

在该片段中,onSelect方法如下:

public void onSelect(){

    new android.os.Handler().postDelayed(
            new Runnable() {
                public void run() {

                    mSwitcher.setText("");

                    mNum = getArguments() != null ? getArguments().getInt("num") : 1;
                    Media currentMedia = slideshow.getMedia().get(mNum);

                    mSwitcher.setText(currentMedia.getDisplayName());
                }
            },
            4000);
}

这种方式的问题在于mSwitcher.setText("");行会抛出一个NullPointerExceptionjava.lang.NullPointerException:尝试调用虚方法'void android.widget.TextSwitcher.setText(java.lang.CharSequence)',其空对象引用 这表明该类中的onCreateView方法尚未运行,因为那里实例化了mSwitcher变量。但这让我感到困惑,因为此时视图已经滑动到屏幕上。
如果您有任何解决此问题的想法,我们将不胜感激。这是我的第一次Android开发经历,我已经尝试了整整一周来解决这个令人恼火的文本淡入问题,但一直没有成功。现在我几乎准备放弃移动平台,因为每个小改变都非常痛苦。

1
“第一页和第二页的onStart/onResume方法同时被调用” - 这是ViewPager与片段(默认情况下)配合使用的方式。 您可以通过https://developer.android.com/reference/android/support/v4/view/ViewPager.html#setOffscreenPageLimit(int)来调整加载多少个屏幕外片段。 - CzarMatt
展示你的片段中的 onCreateView() 方法。 - Daniel Nugent
2个回答

2

我和你一样遇到了相似的问题,onPageSelected()在片段初始化之前被调用,但是你的描述不够详细,比如你如何选择第二个页面。

当适配器使用片段或者说getCount() > 0时,getItem()将返回一个Fragment,该Fragment不为null。但这并不意味着它已经初始化,至少如果你是从FragmentStatePagerAdapter扩展而来的话,它不会。

当适配器提供数据并调用notifyDataSetChange()时,默认情况下适配器将初始化前两个页面。如果你在notifyDataSetChange()后立即调用setCurrentItem()移动到其他页面,可能会出现问题。在运行时,setCurrentItem() -> onPageSelected()可能会在片段初始化之前被调用。

我的解决方案是在setCurrentItem()时使用view.post()。例如:

viewPager.post(() -> viewPager.setCurrentItem(index));

2

ViewPager默认会将下一页保留在内存中,你可以通过调用以下方法进行调整:

viewPager.setOffscreenPageLimit(2);

然而,如果您在上述方法中传递0,这可能没有用处,因为viewPager会忽略它。
您正在朝着正确的方向前进。我相信现在问题出在您的ScreenSlidePagerAdapter上。在getItem(int position)中,您可能有类似以下内容的代码:
if(position == 1)
    return new PageFragment();

可以将适配器更改为以下内容:

public class ScreenSlidePagerAdapter extends FragmentPagerAdapter {

    private List<Fragment> mFragments = new ArrayList<>();

    public ScreenSlidePagerAdapter(FragmentManager fm, List<Item> items) {
        super(fm);

        for (Item item : items) {
            mFragments.add(new PageFragment());
        }
    }


    @Override
    public int getCount() {
        return mFragments.size();
    }

    @Override
    public Fragment getItem(int position) {
        return mFragments.get(position); // Return from list instead of new PagerFragment()
    }
}

是的,这个方法可行。我认为问题在于我的PageFragment类中包含了整个幻灯片而不是每个片段一个媒体对象的引用,但像你所说的更改适配器绝对是必要的。我可以问一下为什么这样做有效,以及您是如何知道这是问题所在的吗?这是因为这种策略确保所有片段都提前创建了吗? - Shawn Mercado
通过这种方式,您始终会获得在ViewPager中充气的片段的相同实例,而当您返回新的MyFragment()时,每次调用它都会获得不同的实例,因此会出现空指针异常。 - Sandip Fichadiya

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接