web-dev-qa-db-ja.com

IllegalStateException:フラグメントのタグを変更できませんAndroid:switcherがAndroid:switcherになりました

私のアクティビティではTabLayout + ViewPagerを使用しています。

ここでのタブとページの数は、サーバーからのデータフェッチに応じて動的です。

クラッシュはCrashlyticsを介して報告されます。複製することはできません。

私の活動コード:

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

完全なスタックトレース:

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

FragmentPagerAdapterはすでにFragmentsをキャッシュしています。各フラグメントにはタグが割り当てられ、FragmentPagerAdapterfindFragmentByTagを呼び出そうとします。 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

メインスレッド: ViewPagerからフラグメントを取得

16
Charuක