我正在使用包含多个 ListView 的 ViewPager
,其代码类似于 Infinite ViewPager 的答案中的代码。 。这个想法是为 Google 日历应用程序提供类似日 View 的东西(其来源似乎不可用;只有默认日历应用程序是,但它使用 ViewSwitcher
) - 我想让它看起来像用户可以无限左右滑动,但 ViewPager 中实际上只有 3 个项目,当用户点击页面 0 或 2 时,我们将 1 设置为当前页面并相应更新。 p>
现在,这一切都有效了。然而,奇怪的是,当手机旋转并重建 Activity 时(我现在避免使用 configChanges ),应用程序中的页面会再次实例化,但顺序不正确。顺序不是 0->1->2,而是 1->0->2,这会打乱应用程序中页面的顺序。
我的 fragment ,在 onActivityCreated()
中:
mPagerAdapter = new ContinuousPagerAdapter(R.layout.my_listview, this);
// set the adapter
mViewPager = (ViewPager) getView().findViewById(R.id.agendaViewPager);
mViewPager.setOffscreenPageLimit(3);
mViewPager.setOnPageChangeListener(this);
mViewPager.setAdapter(mPagerAdapter);
mViewPager.setSaveEnabled(false);
// ...
mViewPager.setCurrentItem(1, false);
loadData();
寻呼机适配器:
import android.content.Context;
import android.os.Parcelable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
public class ContinuousPagerAdapter extends PagerAdapter {
OnPageInstantiatedListener pListener;
ViewPager container;
int childLayoutResId;
@SuppressWarnings("unused")
private ContinuousPagerAdapter() {
}
/**
* @param childLayoutResId Layout resource ID of the children to be inflated
*/
public ContinuousPagerAdapter(int childLayoutResId, OnPageInstantiatedListener pListener) {
this.childLayoutResId = childLayoutResId;
this.pListener = pListener;
}
@Override
public int getCount() {
return 3;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(View container, int position) {
this.container = (ViewPager) container;
// inflate a new child view
LayoutInflater li = (LayoutInflater) container.getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
View childView = li.inflate(childLayoutResId, null, false);
// add it to the view pager and return
int count = this.container.getChildCount();
int actualPos = count > position ? position : count;
this.container.addView(childView, actualPos);
pListener.onPageInstantiated(actualPos); // sometimes use 0 instead of actualPos, with different but still inconsistent results
return childView;
}
@Override
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeViewAt(position);
}
public static interface OnPageInstantiatedListener {
public void onPageInstantiated(int position);
}
/**
* Needed to ensure all the items are instantiated
*/
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
@Override
public Parcelable saveState() {
return null;
}
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
}
@Override
public void finishUpdate(View container) {
}
}
我不明白为什么页面在旋转后会按照1->0->2的顺序实例化。我也不保存状态。对此的任何见解都会有所帮助。
最佳答案
在仔细调试应用程序并查看 ViewPager
源代码后,我发现了问题。
第一次启动应用程序并调用 mViewPager.setAdapter(mPagerAdapter)
时,页面会立即启动,应用程序将按其应有的方式工作。但是,当手机旋转时,调用 setAdapter()
会推迟实例化页面,因为由于窗口尚未准备好,getWindowToken()
返回 null。实例化会被延迟,直到在某个循环中调用之后 onResume()
。
调用 setCurrentItem(1, false)
使第一页成为主页面,因此它在其他页面之前实例化,导致一开始奇怪的 1->0-> 2 实例化。
解决方案?使用 Handler
运行 setCurrentItem()
并在其他页面实例化后加载数据:
new Handler().post(new Runnable() {
@Override
public void run() {
mViewPager.setCurrentItem(1, false);
cleanupAndShowData();
}
});
虽然我通常希望避免使用 Handler
,但这似乎是迄今为止我找到的唯一选择,因为页面本身是添加在循环程序中的。
编辑:即使上述也存在一些问题。仅在实例化所有页面后(在 onPageInstantiated()
中),我最终才调用 mViewPager.setCurrentItem(1, false)
。
关于android - ViewPager 在屏幕旋转后重新实例化无序的项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13585396/