2014-10-14 3 views
0

Когда экран повернут, Android вызывает событие OnPageChangeListener.onPageSelected до вызова FragmentPagerAdapter.instantiateItem.Android ViewPager.OnPageChangeListener проблема вращения жизненного цикла

Это кажется принципиально нарушенным для меня. Обычно я получаю ссылку на фрагмент во время вызова метода instantiateItem. Поскольку onPageSelected вызывается сначала, моя ссылка на фрагмент равна null. Каков наилучший способ обойти эту проблему? См. Ниже код для лучшего объяснения:

(Код написан на C# с использованием Mono для Android, но должен быть почти идентичен эквиваленту 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 
    } 

    ... 
} 

ответ

1

Хотя это, безусловно, чувствует себя сломано, когда этот точный вопрос укусил меня, я думаю, что я понял, «предназначенная модель использования», в которой он фактически не сломан, но работает по назначению. :/

Во-первых, когда пользователь поворачивает устройство и иерархия вид восстанавливается, он никогда не будем называть instantiateItem ... вместо этого он фактически сохраняет и восстанавливает соответствующие фрагменты в рамках FragmentManager (я думаю), чтобы избежать вызова метода instantiateItem. Таким образом, при вызове OnPageSelected нет проблемы с заказом.

В качестве подкласса PagerAdapter с вашим собственным состоянием (а именно, фрагментами) вы несете ответственность за сохранение/восстановление ссылки на сами фрагменты (используя 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); 
      } 

     } 
    } 
} 
+0

Спасибо за отзыв – craigrs84

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 
     } 
    } 

    ... 
} 
Смежные вопросы