ViewPager的第二个片段尚未实例化

时间:2017-02-16 10:46:30

标签: android android-fragments android-viewpager

片段的众多问题之一。 在Activity.onCreate()方法中,我初始化了ViewPager,其中包含两个Fragments

    viewPager = (ViewPager) findViewById(R.id.viewpager);
    viewPager.setOffscreenPageLimit(1);
    adapter = new ViewPagerAdapter(getSupportFragmentManager());
    adapter.addFragment(new AutoFragment(), getString(R.string.song_header_automatic));
    adapter.addFragment(new ManualFragment(), getString(R.string.song_header_manual));
    adapter.notifyDataSetChanged();
    viewPager.setAdapter(adapter);

    TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
    tabLayout.setupWithViewPager(viewPager);

之后,我需要对ViewPager的第二个片段中的View执行操作。

((Fragment) adapter.getItem(1)).getView().findViewById(...)

但它给NPE,因为用户从不浏览到第二个片段,因此它还没有附加。以相同的方式访问第一个片段的元素不会产生任何问题。

不应该setOffscreenPageLimit(1)方法告诉Android还渲染第二个片段吗?

我也尝试不在调用适配器中调用destroyItem的超级方法,但没有运气,因为问题是片段甚至没有被初始化。

public class ViewPagerAdapter extends FragmentStatePagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

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

    public void addFragment(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitleList.get(position);
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {}
}

如何强制它以便渲染不可见的片段?

注意:此问题有时仅发生在应用用户身上,我无法重现。只有在我遇到这个问题后,我认为所有这些都是在正确的生命周期事件之后执行错误操作。

1 个答案:

答案 0 :(得分:0)

作为FragmentStatePagerAdapter的文档:

  

当有大量的寻呼机时,此版本的寻呼机更有用   页面,更像列表视图。当页面不可见时   用户,他们的整个片段可能会被破坏,只保留   保存了该片段的状态。这允许寻呼机保持很多   与每个访问页面相关联的内存较少   FragmentPagerAdapter的代价可能是更多的开销   在页面之间切换。

您可以尝试使用FragmentPagerAdapter

编辑:

由于它发生在少数设备上,我猜它是一个低内存设备。

您可能会尝试重新加载第二个片段,并将args传递给它。

在适配器上,实现一个替换片段的方法:

public void replaceFragment(int index, Fragment fragment, String title) {
    mFragmentList.set(index, fragment);
    mFragmentTitleList.add(index, title);
}

如果要使用新数据重新加载第二个片段,请执行以下操作:

Bundle fragmentArgs = new Bundle();
fragmentArgs.putSerializable("obj", obj); //data you want to pass
fragmentArgs.putString("str", str); //data you want to pass
ManualFragment manualFragment = new ManualFragment();
manualFragment.setArguments(fragmentArgs);

adapter.replaceFragment(1, manualFragment, getString(R.string.song_header_manual));
adapter.notifyDataSetChanged();

然后在onCreateView的{​​{1}},获取参数:

ManualFragment

做任何你必须做的事。

编辑2:

由于OP想要另一种方法,这里就是......

做这样的回答:https://stackoverflow.com/a/24343211/2174489

这样您就不会从原始范围之外的其他片段访问视图。我不喜欢像Object obj = (Object) getArguments().getSerializable("obj"); String str = getArguments().getString("str"); 这样的想法。我宁愿做((Fragment) adapter.getItem(1)).getView().findViewById(...)

然后,在((Fragment) adapter.getItem(1)).setTextViewText(...),您可以测试您的视图是否为空。如果为null,则将字符串保存在全局变量中:

setTextViewText

然后在public void setTextViewText(String value){ if (mTextView == null) myGlobalValue = value; else mTextView.setText(value); } ,您可以设置该值:

onCreateView

如果能解决问题,请告诉我。