Android的ViewPager setCurrentItem后onResume不工作

我得到了这个奇怪的问题,ViewPager的setCurrentItem(position,false)完美地工作,然后切换到另一个活动,并且在回到第一个活动后,ViewPager总是在第一个项目上结束。 即使ive添加setCurrentItem到onResume方法它仍然忽略它。 它甚至不会抛出任何exception,当我试图设置项目越界索引。 虽然后来我调用这个方法的时候,点击button“下一步”,它按预期工作。 检查我的代码10次任何可能的调用setCurrentItem(0)或水手,但它根本不存在。

我不能真正回答为什么会发生这种情况,但如果您延迟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行动,我searchstackoverflow的解决scheme。 我发现一个人有同样的问题和解决办法; 我执行了修复程序,它不起作用。 哇! 回到stackoverflow downvote人造固定提供商,和…

那是我。 我实施了我自己的错误的无法解决,我第一次想到了这个问题(后来被遗忘)。 我现在必须自己提供坏信息。


我最初的“修复”工作的原因不是因为“渲染通行证”; 问题是传呼机的内容是由微调控制的。 spinners和pagers状态都恢复了onResume,因此在下一个事件传播周期中调用了ItemSelected监听器上的debugging器,它重新填充了viewpager – 这次使用了不同的默认值。
在初始状态恢复期间移除和重置听众固定了问题。

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

更新2:我不能downvote自己的职位。 我认为,尊贵的seppuku是唯一的select。

我在我的Activity的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。

对于我来说这个工作设置适配器后设置当前项目

 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 deprecation是因为在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的解决scheme是不可预测的, 可能还有错误发生。 这似乎是通过将其发布到未来来忽略问题的一种方式。

我并不是说这是最好的解决scheme,但它确实可以不使用Runnable 。 我有一个单独的整数在具有ViewPagerFragment下一次调用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() ,视图即将被重新创build。 所以实际上,我为viewpager调用setCurrentItem() ,然后系统调用onCreateView()并因此创build一个新的viewpager。

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

理论上的解决scheme:推迟setCurrentItem()调用,直到重新创build视图。

实用的解决scheme:我不知道一个稳定而简单的解决scheme。 我们应该能够检查类是否要重新创build它的视图,如果是这样的话,将setCurrentItem()的调用推迟到onCreateView()

您需要在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); }