onResume后,Android ViewPager setCurrentItem无法正常工作

我有这个奇怪的问题,ViewPager的setCurrentItem(position,false)工作得很好,然后我切换到另一个活动,并且在我回到第一个活动后,ViewPager总是在第一个项目上结束。 即使我已将setCurrentItem添加到onResume方法,它仍然会忽略它。 当我试图将项目设置为越界索引时,它甚至没有抛出任何exception。 虽然稍后当我调用此方法时,单击按钮“next”时,它会按预期工作。 检查我的代码10次,以获得对setCurrentItem(0)或smth的任何可能调用,但它根本就没有。

我无法回答为什么会发生这种情况,但是如果你将setCurrentItem调用延迟几毫秒就可以了。 我的猜测是因为在onResume期间还没有渲染过程,而ViewPager需要一个或类似的东西。

 private ViewPager viewPager; @Override public void onResume() { final int pos = 3; viewPager.postDelayed(new Runnable() { @Override public void run() { viewPager.setCurrentItem(pos); } }, 100); } 

更新:故事时间

所以今天我遇到了viewpager忽略了我的setCurrentItem动作的问题,我搜索了stackoverflow的解决方案。 我find了一个有同样问题和解决方法的人; 我实现了修复,它没有工作。 哇! 回到stackoverflow来downvote那个faux-fix-provider,并且……

那是我。 我实现了我自己的错误的非修复,我第一次偶然发现问题(后来被遗忘)。 我现在不得不向自己提供不良信息。


我最初的“修复”工作的原因不是因为“渲染过程”; 问题是寻呼机的内容是由微调器控制的。 旋转器和寻呼机状态都在onResume上被恢复,因此在下一个事件传播周期中调用了旋转器onItemSelected侦听器,它确实重新填充了viewpager – 这次使用了不同的默认值。
在初始状态恢复期间移除和重置监听器解决了问题。

上面的修复工作是第一次,因为它在onItemSelected事件触发设置了寻呼机的当前位置。 后来,它由于某种原因停止工作(可能应用程序变得太慢 – 在我的实现中我没有使用100毫秒,但10毫秒)。 然后我在清理周期中删除了postDelayed,因为它没有改变已经存在的错误行为。

更新2:我不能低估自己的post。 我认为,尊贵的seppuku是唯一的选择。

我的活动OnCreate中有类似的问题。 使用正确的计数设置适配器,并在将适配器设置为ViewPager后应用setCurrentItem,但是将返回索引超出范围。 我认为ViewPager在我设置当前项目时没有加载我的所有片段。 通过在ViewPager上发布runnable,我能够解决这个问题。 这是一个带有一点上下文的例子。

  // Locate the viewpager in activity_main.xml final ViewPager viewPager = (ViewPager) findViewById(R.id.pager); // Set the ViewPagerAdapter into ViewPager viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager())); viewPager.setOffscreenPageLimit(2); viewPager.post(new Runnable() { @Override public void run() { viewPager.setCurrentItem(ViewPagerAdapter.CENTER_PAGE); } }); 

我发现了一个非常简单的解决方法:

  if (mViewPager.getAdapter() != null) mViewPager.setAdapter(null); mViewPager.setAdapter(mPagerAdapter); mViewPager.setCurrentItem(desiredPos); 

并且,如果这不起作用,您可以将它放在处理程序中,但不需要定时延迟:

  new Handler().post(new Runnable() { @Override public void run() { mViewPager.setCurrentItem(desiredPos); } }); 

我有同样的问题,我编辑

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

我将NUM_PAGES错误设置为1。

我在代码中有类似的错误,问题是我在更改数据之前设置了位置。

解决方案只是稍后设置位置并通知更改的数据

 notifyDataSetChanged() setCurrentItem() 

对我来说,这在设置适配器后设置当前项目

 viewPager.setAdapter(new MyPagerAdapter(getSupportFragmentManager())); viewPager.setCurrentItem(idx); pagerSlidingTabStrip.setViewPager(viewPager);// assign viewpager to tabs 

我已经使用了这里描述的post()方法,并确定它在某些情况下工作得很好但是因为我的数据来自服务器,所以它不是圣杯。

我的问题是我想拥有

 notifyDataSetChanged 

在任意时间调用,然后在我的viewPager上切换标签。 所以在通知电话之后,我有这个

 ViewUtilities.waitForLayout(myViewPager, new Runnable() { @Override public void run() { myViewPager.setCurrentItem(tabIndex , false); } }); 

 public final class ViewUtilities { public static void waitForLayout(final View view, final Runnable runnable) { view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { //noinspection deprecation view.getViewTreeObserver().removeGlobalOnLayoutListener(this); runnable.run(); } }); } } 

有趣的事实: //最后的noinspection弃用是因为在API 16之后修复了API中的拼写错误,所以应该读取删除On GlobalLayoutListener而不是removeGlobal LayoutListener上

这似乎涵盖了我的所有案例。

我这样做是为了恢复当前项目:

 @Override protected void onSaveInstanceState(Bundle outState) { if (mViewPager != null) { outState.putInt(STATE_PAGE_NO, mViewPager.getCurrentItem()); } super.onSaveInstanceState(outState); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { if (savedInstanceState != null) { mCurrentPage = savedInstanceState.getInt(STATE_PAGE_NO, 0); } super.onRestoreInstanceState(savedInstanceState); } @Override protected void onRestart() { mViewPager.setCurrentItem(mCurrentPage); super.onRestart(); } 

这是一个生命周期问题,正如这里的几个海报所指出的那样。 但是,我发现发布Runnable的解决方案不可预测且可能容易出错。 这似乎是一种通过将其发布到未来来忽略该问题的方法。

我并不是说这是最好的解决方案,但它确实可以在不使用Runnable 。 我在Fragment中保留了一个包含ViewPager的单独整数。 当接下来调用onResume时,此整数将保存我们要设置为当前页面的页面。 整数的值可以在任何点设置,因此可以在FragmentTransaction之前或恢复活动时设置。 另请注意,所有成员都在onResume()中设置,而不是在onCreateView()

 public class MyFragment extends Fragment { private ViewPager mViewPager; private MyPagerAdapter mAdapter; private TabLayout mTabLayout; private int mCurrentItem = 0; // Used to keep the page we want to set in onResume(). @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.my_layout, container, false); mViewPager = (ViewPager) view.findViewById(R.id.my_viewpager); mTabLayout = (TabLayout) view.findViewById(R.id.my_tablayout); return view; } @Override public void onResume() { super.onResume(); MyActivity myActivity = (MyActivity) getActivity(); myActivity.getSupportActionBar().setTitle(getString(R.string.my_title)); mAdapter = new MyPagerAdapter(getChildFragmentManager(), myActivity); mViewPager.setAdapter(mAdapter); mViewPager.setOffscreenPageLimit(PagerConstants.OFFSCREEN_PAGE_LIMIT); mViewPager.setCurrentItem(mCurrentItem); // < -- Note the use of mCurrentItem here! mTabLayout.setupWithViewPager(mViewPager); } /** * Call this at any point before needed, for example before performing a FragmentTransaction. */ public void setCurrentItem(int currentItem) { mCurrentItem = currentItem; // This should be called in cases where onResume() is not called later, // for example if you only want to change the page in the ViewPager // when clicking a Button or whatever. Just omit if not needed. mViewPager.setCurrentItem(mCurrentItem); } } 

当我调用setCurrentItem() ,即将重新创建视图。 所以实际上我为viewpager调用setCurrentItem() ,然后系统调用onCreateView() ,从而创建一个新的viewpager。

这就是为什么我没有看到任何变化的原因。 这就是postDelayed()可能postDelayed()的原因。

理论解决方案:推迟setCurrentItem()调用,直到重新创建视图。

实用的解决方案:我不知道一个稳定而简单的解决方案。 我们应该能够检查类是否要重新创建它的视图,如果是这种情况,则将setCurrentItem()的调用推迟到onCreateView()的末尾

有人在这里的论坛上写道。 https://code.i-harness.com/en/q/126bff9为我工作

  if (mViewPager.getAdapter() != null) mViewPager.setAdapter(null); mViewPager.setAdapter(mPagerAdapter); mViewPager.setCurrentItem(desiredPos); 

清除和简单在调用notifyDataSetChanged()之后,无需在setCurrentItem中添加post方法。

你需要在pager.setAdapter(buildAdapter())之后调用pager.setCurrentItem(activePage)

 @Override public void onResume() { if (pager.getAdapter() != null) { activePage=pager.getCurrentItem(); Log.w(getClass().getSimpleName(), "pager.getAdapter()!=null"); pager.setAdapter(null); } pager.setAdapter(buildAdapter()); pager.setCurrentItem(activePage); }