当屏幕旋转时,Android会在调用FragmentPagerAdapter.instantiateItem之前调用OnPageChangeListener.onPageSelected事件。
这似乎从根本上打破了我。我通常在调用instantiateItem期间获得对片段的引用。由于首先调用onPageSelected,因此我对片段的引用为null。解决此问题的最佳方法是什么?请参阅下面的代码以获得更好的解释:
(代码是使用Mono for Android用C#编写的,但应该与Java等价的几乎相同)。
适配器:
public class MainPagerAdapter : FragmentPagerAdapter
{
public Fragment[] Fragments { get; private set; }
public override Java.Lang.Object InstantiateItem(ViewGroup view, int index)
{
var o = base.InstantiateItem(view, index);
Fragments[index] = (Fragment)o;
return o;
}
...
}
监听器:
public class TabPagerListener : Java.Lang.Object, ViewPager.IOnPageChangeListener, TabPageIndicator.IOnTabReselectedListener
{
public void OnPageSelected(int tabIndex)
{
var tabActivity = (ITabActivity)Instance;
var currentFragment = TabAdapter.Fragments[TabPager.CurrentItem];
//currentFragment will be null since InstantiateItem hasn't been called yet
}
...
}
答案 0 :(得分:1)
虽然这个确切的问题让我感觉很糟糕,但我认为我已经找到了“预期的使用模式”,其中它实际上没有被打破,而是按预期工作。 :/
首先,当用户旋转设备并重建视图层次结构时,永远不会将调用instantiateItem ...而是实际上将相关片段保存并恢复为FragmentManager的一部分(我认为),以避免调用instantiateItem。因此,对OnPageSelected的调用没有“排序”问题。
作为具有您自己状态的PagerAdapter的子类(即Fragments),您负责自己保存/恢复对片段的引用(使用传递给构造函数的FragmentManager)。我相信以下内容应该适用于FragmentStatePagerAdapter 和 FragmentPagerAdapter子类:
public EventInfoPagerAdapter(FragmentManager fm) {
super(fm);
mFragmentManager = fm;
}
private static String STATE_SUPERCLASS = "STATE_SUPERCLASS";
private static String STATE_FRAGMENT_IDS = "STATE_FRAGMENT_IDS";
@Override
public Parcelable saveState() {
Parcelable p = super.saveState();
Bundle bundle = new Bundle();
bundle.putParcelable(STATE_SUPERCLASS, p);
Bundle fragmentsBundle = new Bundle();
for (int i=0; i<mFragments.size(); i++) {
Fragment f = mFragments.get(i);
if (f != null) {
mFragmentManager.putFragment(fragmentsBundle, Integer.toString(i), f);
}
}
bundle.putBundle(STATE_FRAGMENT_IDS, fragmentsBundle);
return bundle;
}
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
Bundle bundle = (Bundle)state;
if (bundle != null) {
super.restoreState(bundle.getParcelable(STATE_SUPERCLASS), loader);
Bundle fragmentsBundle = bundle.getBundle(STATE_FRAGMENT_IDS);
mFragments.clear();
mFragments.ensureCapacity(fragmentsBundle.size());
Iterable<String> keys = fragmentsBundle.keySet();
for (String key: keys) {
int index = Integer.parseInt(key);
Fragment f = mFragmentManager.getFragment(fragmentsBundle, key);
if (f != null) {
while (mFragments.size() <= index) {
mFragments.add(null);
}
FragmentCompat.setMenuVisibility(f, false);
mFragments.set(index, (EventInfoFragment)f);
} else {
Log.w(LOG_TAG, "Bad fragment at key " + key);
}
}
}
}
答案 1 :(得分:1)
仅供参考,我还提出了以下解决方法:
public class TabPagerListener : Java.Lang.Object, ViewPager.IOnPageChangeListener, TabPageIndicator.IOnTabReselectedListener
{
public ViewPager ViewPager { get; set; }
public void OnPageSelected(int tabIndex)
{
ViewPager.Post(() => //this causes action to be delayed until after fragment is resumed
{
var tabActivity = (ITabActivity)Instance;
var currentFragment = TabAdapter.Fragments[TabPager.CurrentItem];
//currentFragment is not null, InstantiateItem was already called
}
}
...
}