Android ViewPager setCurrentItem在onResume之后不工作
我遇到了一个奇怪的问题,Android ViewPager setCurrentItem在onResume之后不工作,android,methods,android-viewpager,onresume,Android,Methods,Android Viewpager,Onresume,我遇到了一个奇怪的问题,ViewPager的setCurrentItem(position,false)工作得非常好,然后我切换到另一个活动,在我返回到第一个活动后,ViewPager总是在第一个项目上结束。即使我将setCurrentItem添加到onResume方法中,它仍然会忽略它。当我试图将项设置为越界索引时,它甚至不会抛出任何异常。 虽然稍后我调用此方法时,当点击“下一步”按钮时,它的工作方式与预期相同。 对我的代码进行了10次检查,查看是否存在对setCurrentItem(0)或其
ViewPager
的setCurrentItem(position,false)
工作得非常好,然后我切换到另一个活动,在我返回到第一个活动后,ViewPager
总是在第一个项目上结束。即使我将setCurrentItem
添加到onResume
方法中,它仍然会忽略它。当我试图将项设置为越界索引时,它甚至不会抛出任何异常。
虽然稍后我调用此方法时,当点击“下一步”按钮时,它的工作方式与预期相同。
对我的代码进行了10次检查,查看是否存在对
setCurrentItem(0)
或其他任何可能的调用,但它根本不在那里。我这样做是为了还原当前项目:
@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();
}
我不能确切地回答为什么会发生这种情况,但是如果您将setCurrentItem调用延迟几毫秒,它应该可以工作。我猜这是因为在恢复过程中还没有渲染过程,而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以寻找解决方案。我发现有人有同样的问题和解决办法;我实施了修复,但它不起作用。哇!返回stackoverflow以否决该错误修复提供程序,然后
是我。我实现了自己的错误非修复,这是我第一次遇到问题时提出的(后来被遗忘)。我现在不得不对自己提供的坏消息投反对票
我最初的“修复”工作的原因不是因为“渲染过程”;问题是寻呼机的内容是由旋转器控制的。微调器和寻呼机状态都在恢复时恢复,因此在下一个事件传播周期中调用了微调器选定的侦听器,这确实重新填充了viewpager-这次使用了不同的默认值。
在初始状态恢复期间删除并重置侦听器修复了该问题 上述修复第一次起作用,因为它在触发onItemSelected事件后将寻呼机设置为当前位置。后来,由于某种原因,它停止了工作(可能是应用程序太慢了——在我的实现中,我没有使用100毫秒,而是使用10毫秒)。然后,我在一个清理周期中删除了postDelayed,因为它没有改变已经出现错误的行为
更新2:我不能否决我自己的帖子。我想,尊敬的塞普库是唯一剩下的选择。我找到了一个非常简单的解决方法:
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);
}
});
您需要在pager.setAdapter(buildAdapter())之后调用pager.setCurrentItem(activePage)
我有同样的问题,我编辑
@Override
public int getCount() { return NUM_PAGES; }
我将
NUM\u PAGES
设置为1 only。我在创建活动时遇到了类似的问题。
适配器设置了正确的计数,并且
将适配器设置为后应用了setCurrentItem
然而,ViewPager将返回超出范围的索引。我想在我设置当前项时,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);
}
});
这是一个生命周期问题,正如这里的几张海报所指出的。然而,我发现发布
Runnable
的解决方案是不可预测的,而且可能容易出错。这似乎是一种通过将问题发布到未来来忽略问题的方法
我并不是说这是最好的解决方案,但它肯定不使用Runnable
。我在片段
中保留了一个单独的整数,该片段具有查看页面
下一步调用onResume
时,此整数将保留我们要设置为当前页面的页面。整数的值可以在任何点设置,因此可以在碎片事务之前或恢复活动时设置。还要注意,所有成员都是在onResume()
中设置的,而不是在onCreateView()中设置的
公共类MyFragment扩展了片段
{
私有视图寻呼机mViewPager;
私人MyPagerAdapter mAdapter;
私人小报;
private int mCurrentItem=0;//用于保留要在onResume()中设置的页面。
@可空
@凌驾
CreateView上的公共视图(布局、充气机、视图组容器、捆绑包保存状态)
{
视图=充气机。充气(R.layout.my_布局,容器,假);
mViewPager=(ViewPager)view.findViewById(R.id.my_ViewPager);
mTabLayout=(TabLayout)view.findViewById(R.id.my_TabLayout);
返回视图;
}
@凌驾
恢复时公开作废()
{
super.onResume();
MyActivity MyActivity=(MyActivity)getActivity();
myActivity.getSupportActionBar().setTitle(getString(R.string.my_title));
mAdapter=新的MyPagerAdapter(getChildFragmentManager(),myActivity);
mViewPager.setAdapter(mAdapter);
mViewPager.setOffscreenPageLimit(页面切换、屏幕外页面限制);
mViewPager.setCurrentItem(mCurrentItem);//对于我来说,在设置适配器之后,设置当前项是有效的
viewPager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));
viewPager.setCurrentItem(idx);
pagerSlidingTabStrip.setViewPager(viewPager);// assign viewpager to tabs
当我调用setCurrentItem()
时,视图即将重新创建。因此,事实上,我为viewpager调用了setCurrentItem()
,然后系统调用onCreateView()
,从而创建了一个新的viewpager
这就是为什么我看不到任何更改的原因。这也是为什么postDelayed()
可能会有所帮助的原因
理论解决方案:推迟调用setCurrentItem()
直到重新创建视图
实践
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);
}
}
viewPager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));
viewPager.setCurrentItem(idx);
pagerSlidingTabStrip.setViewPager(viewPager);// assign viewpager to tabs
notifyDataSetChanged
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();
}
});
}
}
removeOnGlobalLayoutListener
^^
ON Global
removeGlobalOnLayoutListener
^^
ON Layout
notifyDataSetChanged()
setCurrentItem()
if (mViewPager.getAdapter() != null)
mViewPager.setAdapter(null);
mViewPager.setAdapter(mPagerAdapter);
mViewPager.setCurrentItem(desiredPos);
class MyActivity : AppCompatActivity() {
lateinit var mAdapter: MyAdapter
lateinit var mPager: ViewPager
// ...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.fragment_pager)
// ...
mainViewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
mAdapter = MyAdapter(supportFragmentManager)
mPager = findViewById(R.id.pager)
mainViewModel.someData.observe(this, Observer { items ->
items?.let {
// first give the data to the adapter
// this is where the notifyDataSetChanged() happens
mAdapter.setItems(it)
mPager.adapter = mAdapter // assign adapter to pager
mPager.currentItem = idx // finally set the current page
}
})
internal fun setItems(items: List<Item>) {
this.items = items
notifyDataSetChanged()
}
lifecycleScope.launch(Dispatchers.Main) {
val index = 1
viewPager.setCurrentItem(index)
}
view_pager.doOnPreDraw {
view_pager.currentItem = 1
}
if (myXXRecyclerAdapter != null) {
myXXRecyclerAdapter = new MyXXRecyclerAdapter(myStoredData);
mRecyclerView.setAdapter(myXXRecyclerAdapter );
return;
}