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