IllegalStateException:无法更改片段的标签以前 android:switcher 现在 android:switcher

IllegalStateException: Can't change tag of fragment was android:switcher now android:switcher

我的 activity 使用 TabLayout + ViewPager.

此处的选项卡和页面数量是动态的,具体取决于从服务器获取的数据。

崩溃是通过 Crashlytics 报告的,我无法复制它。

我的Activity代码:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        boolean isAppRestarting = PrefUtils.getBoolean("app_restarting", false);
        if (isAppRestarting) {
            super.onCreate(null);
            this.savedInstanceState = null;
        } else {
            super.onCreate(savedInstanceState);
            this.savedInstanceState = savedInstanceState;
        }

        initSlidingTabs();

        fetchSomeData(); // see onDataFetched() below
    }

private void initSlidingTabs() {
        List<FragmentWithTitle> sdsTabs = new ArrayList<>();
            Logger.i("There is saved instance state");
            ArrayList<String> titles = savedInstanceState.getStringArrayList(TAB_TITLES);
            if (titles != null) {
                for (int i = 0; i < titles.size(); i++) {
                    if (getFragment(i) != null) {
                        sdsTabs.add(new FragmentWithTitle(getFragment(i), titles.get(i)));
                    }
                }
            }

        mTabsAdapter = new MyTabsAdapter(getSupportFragmentManager(), sdsTabs);

        mViewPager = (ViewPager) findViewById(R.id.layoutViewPagerSlidingTabs);
        mViewPager.setAdapter(mTabsAdapter);
        mViewPager.setOffscreenPageLimit(2);

        mSlidingTabs = (TabLayout) findViewById(R.id.tabs);
        mSlidingTabs.setupWithViewPager(mViewPager);
}

@Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (mTabsAdapter != null) {
            outState.putStringArrayList(TAB_TITLES, mTabsAdapter.getTitles());
        }
    }

    private Fragment getFragment(int position) {
        return savedInstanceState == null ? mTabsAdapter.getItem(position) : getSupportFragmentManager()
                .findFragmentByTag(getFragmentTag(position));
    }

    private String getFragmentTag(int position) {
        return "android:switcher:" + R.id.layoutViewPagerSlidingTabs + ":" + position;
    }

/**
Callback of fetchData() in onCreate()
*/
private void onDataFetched(List<AbcObject> abcObjects) {
        if (savedInstanceState == null) {
            if (abcObjects != null) {
                for (AbcObject abcObject : abcObjects) {
                    mTabsAdapter.addTab(new FragmentWithTitle(AbcFragment.newInstance(), abcObject.getTitle()));
                }
            }
        } else {
            Logger.d("There is saved instance state");
            ArrayList<String> titles = savedInstanceState.getStringArrayList(TAB_TITLES);
            if (titles != null) {
                for (int i = 0; i < titles.size(); i++) {
                    mTabsAdapter.addTab(new FragmentWithTitle(getFragment(i), titles.get(i)));
                }
            }
        }

        mTabsAdapter.notifyDataSetChanged();
    }

MyTabs 适配器:

public class MyTabsAdapter extends FragmentPagerAdapter {

    private List<FragmentWithTitle> mTabs = new ArrayList<>();

    public MyTabsAdapter(FragmentManager fm, List<FragmentWithTitle> sdsTabs) {
        super(fm);
        this.mTabs = sdsTabs;
    }

    @Override
    public Fragment getItem(int position) {
        return mTabs.get(position).getFragment();
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mTabs.get(position).getTitle();
    }

    @Override
    public int getCount() {
        return this.mTabs.size();
    }

    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

    /**
     * Prevent java.lang.IllegalStateException Fragment no longer exists for key android:target_state: index 5
     *
     * @return
     */
    @Override
    public Parcelable saveState() {
        return null;
    }

    public ArrayList<String> getTitles() {
        ArrayList<String> titles = new ArrayList<>();
        for (int i = 0; i < mTabs.size(); i++) {
            titles.add((String) mTabs.get(i).getTitle());
        }
        return titles;
    }

    public void addTab(FragmentWithTitle fragmentWithTitle) {
        mTabs.add(fragmentWithTitle);
    }
}

完整堆栈跟踪:

Fatal Exception: java.lang.IllegalStateException: Can't change tag of fragment ShopFrag{4dbb6e90 #0 id=0x7f1200dd android:switcher:2131886301:0}: was android:switcher:2131886301:0 now android:switcher:2131886301:9
       at android.support.v4.app.BackStackRecord.doAddOp(BackStackRecord.java:444)
       at android.support.v4.app.BackStackRecord.add(BackStackRecord.java:426)
       at android.support.v4.app.FragmentPagerAdapter.instantiateItem(FragmentPagerAdapter.java:103)
       at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:1038)
       at android.support.v4.view.ViewPager.populate(ViewPager.java:1252)
       at android.support.v4.view.ViewPager.populate(ViewPager.java:1120)
       at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1646)
       at android.view.View.measure(View.java:17396)
       at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5365)
       at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1410)
       at android.widget.LinearLayout.measureVertical(LinearLayout.java:695)
       at android.widget.LinearLayout.onMeasure(LinearLayout.java:588)
       at android.view.View.measure(View.java:17396)
       at android.support.v4.widget.DrawerLayout.onMeasure(DrawerLayout.java:1081)
       at android.view.View.measure(View.java:17396)
       at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5365)
       at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
       at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:139)
       at android.view.View.measure(View.java:17396)
       at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5365)
       at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1410)
       at android.widget.LinearLayout.measureVertical(LinearLayout.java:695)
       at android.widget.LinearLayout.onMeasure(LinearLayout.java:588)
       at android.view.View.measure(View.java:17396)
       at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5365)
       at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
       at android.view.View.measure(View.java:17396)
       at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5365)
       at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1410)
       at android.widget.LinearLayout.measureVertical(LinearLayout.java:695)
       at android.widget.LinearLayout.onMeasure(LinearLayout.java:588)
       at android.view.View.measure(View.java:17396)
       at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5365)
       at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
       at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2505)
       at android.view.View.measure(View.java:17396)
       at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2175)
       at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1316)
       at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1513)
       at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1200)
       at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6401)
       at android.view.Choreographer$CallbackRecord.run(Choreographer.java:803)
       at android.view.Choreographer.doCallbacks(Choreographer.java:603)
       at android.view.Choreographer.doFrame(Choreographer.java:573)
       at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:789)
       at android.os.Handler.handleCallback(Handler.java:733)
       at android.os.Handler.dispatchMessage(Handler.java:95)
       at android.os.Looper.loop(Looper.java:157)
       at android.app.ActivityThread.main(ActivityThread.java:5335)
       at java.lang.reflect.Method.invokeNative(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:515)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
       at dalvik.system.NativeStart.main(NativeStart.java)

带有标题的片段:

public class FragmentWithTitle {
    public FragmentWithTitle(Fragment mFragment, CharSequence mTitle) {
        this.fragment = mFragment;
        this.title = mTitle;
    }

    public Fragment getFragment() {
        return fragment;
    }

    public void setFragment(Fragment fragment) {
        this.fragment = fragment;
    }

    public CharSequence getTitle() {
        return title;
    }

    public void setTitle(CharSequence title) {
        this.title = title;
    }

    private Fragment fragment;
    private CharSequence title;
}

FragmentPagerAdapter 已经为您缓存了 Fragments。每个片段都分配了一个标签,然后 FragmentPagerAdapter 尝试调用 findFragmentByTag。如果 findFragmentByTag 的结果是 null.

,它只会调用 getItem()

您可能会收到此错误,因为您正在将相同的片段实例添加到列表中。您应该为每个页面创建一个新实例

示例表单文档:

//...
      public static class MyAdapter extends FragmentPagerAdapter {
            public MyAdapter(FragmentManager fm) {
                super(fm);
            }

            @Override
            public int getCount() {
                return NUM_ITEMS;
            }

            @Override
            public Fragment getItem(int position) {
                return ArrayListFragment.newInstance(position);// IMPORTANT
            }
        }
    //..

参考:FragmentPagerAdapter

主线程:Retrieve a Fragment from a ViewPager