web-dev-qa-db-fra.com

IllegalStateException: Impossible de modifier la balise du fragment était Android: commutateur maintenant Android: commutateur

Mon activité utilise TabLayout + ViewPager.

Le nombre d'onglets et de pages ici est dynamique en fonction de l'extraction des données du serveur.

Les plantages sont signalés via Crashlytics, je ne suis pas en mesure de les reproduire.

Mon code d'activité:

@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();
    }

MyTabsAdapter:

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

Trace de pile complète:

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)

FragmentWithTitle:

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

Le FragmentPagerAdapter met déjà en cache le Fragments pour vous. Chaque fragment se voit attribuer une balise, puis le FragmentPagerAdapter essaie d'appeler findFragmentByTag. Il n'appelle getItem () que si le résultat de findFragmentByTag est null.

Vous obtenez probablement cette erreur car vous ajoutez la même instance de fragment à la liste. Vous devez créer une nouvelle instance pour chaque page.

Exemple de document de formulaire:

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

Voir: FragmentPagerAdapter

Fil principal: Récupérer un fragment d'un ViewPager

16
Charuක