简体   繁体   English

Android ViewPager.OnPageChangeListener生命周期轮换问题

[英]Android ViewPager.OnPageChangeListener lifecycle rotation issue

When the screen is rotated Android calls the OnPageChangeListener.onPageSelected event prior to calling FragmentPagerAdapter.instantiateItem. 旋转屏幕时,Android在调用FragmentPagerAdapter.instantiateItem之前先调用OnPageChangeListener.onPageSelected事件。

This seems fundamentally broken to me. 这似乎从根本上打破了我的观点。 I typically get a reference to the fragment during the call to instantiateItem. 我通常在调用InstantiateItem的过程中获得对该片段的引用。 Since onPageSelected is called first my reference to the fragment is null. 由于首先调用onPageSelected,因此我对该片段的引用为null。 What's the best way to work around this problem? 解决此问题的最佳方法是什么? See code below for a better explanation: 请参阅下面的代码以获得更好的解释:

(Code is written in C# using Mono for Android but should be nearly identical to the Java equivalent). (代码是使用Android的Mono使用C#编写的,但应该与Java等价物几乎相同)。

Adapter: 适配器:

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

    ...
}

Listener: 听众:

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
    }

    ...
}

While it definitely feels broken when this exact issue bit me, I think I've figured out the "intended usage model", in which it's not actually broken but working as intended. 当这个确切的问题困扰我时,它肯定感觉很破损,但我认为我已经弄清楚了“预期的使用模型”,在该模型中,它实际上并没有损坏,但是可以按预期工作。 :/ :/

First, when the user rotates the device and the view hierarchy is reconstructed, it never will call instantiateItem...instead it actually saves and restores the relevant fragments as part of the FragmentManager (I think), to avoid calling instantiateItem. 首先,当用户旋转设备并重建视图层次结构时,它将永远不会调用InstantiateItem ...而是实际上将相关片段作为FragmentManager的一部分进行保存和恢复(我认为),以避免调用InstantiateItem。 So there is no "ordering" problem with the call to OnPageSelected. 因此,对OnPageSelected的调用没有“排序”问题。

As a subclasser of PagerAdapter with your own state (namely, Fragments), you are responsible for saving/restoring your reference to the fragments yourself (using the FragmentManager that gets passed in to the constructor). 作为具有您自己的状态(即片段)的PagerAdapter的子类,您有责任自己保存/恢复对片段的引用(使用传递给构造函数的FragmentManager)。 I believe the following should work for both FragmentStatePagerAdapter and FragmentPagerAdapter subclasses: 我相信以下内容对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);
            }

        }
    }
}

Just for reference, I also came up with the following workaround: 仅供参考,我还提出了以下解决方法:

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

    ...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 ViewPager.OnPageChangeListener中的片段接口 - Interface in fragment in ViewPager.OnPageChangeListener 如何使用ViewPager.OnPageChangeListener - How to work with ViewPager.OnPageChangeListener 带有ViewPager.OnPageChangeListener的ActionBarSherlock TabPageIndicator-标签卡住了 - ActionBarSherlock TabPageIndicator with ViewPager.OnPageChangeListener - tab is stuck ViewPager.OnPageChangeListener给出错误的位置 - ViewPager.OnPageChangeListener giving wrong position ViewPager.OnPageChangeListener在ViewPager完成初始化之前运行 - ViewPager.OnPageChangeListener runs before ViewPager finish init 构造函数Intent(new ViewPager.OnPageChangeListener(){},类 <Player> )未定义 - The constructor Intent(new ViewPager.OnPageChangeListener(){}, Class<Player>) is undefined 以编程方式在ViewPager.OnPageChangeListener onPageSelected()中隐藏软键盘? - Programmatically Hide Soft Keyboard in ViewPager.OnPageChangeListener onPageSelected()? 如何拦截ViewPager.OnPageChangeListener中的触摸事件 - How to intercept touch events from ViewPager.OnPageChangeListener Android:Viewpager OnPageChangeListener onpageselected扰乱了幻灯片动画 - Android: Viewpager OnPageChangeListener onpageselected disturbs slide animation Android从片段中检测ViewPager上的OnPageChangeListener - Android detecting OnPageChangeListener on a ViewPager from within a fragment
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM