关于Fragment already added问题的解决方案

关于Fragment already added问题的解决方案

目录

Fragment already added问题解决

问题

方法

java.lang.IllegalStateException: Fragment already added 异常处理

小结一下

Fragment already added问题解决 问题

当快速点击切换不同的Fragment的时候部分手机的app竟然挂了,

报出了下面的错误 Fragment already added

java.lang.IllegalStateException: Fragment already added: xxxxFragment

上网找了很多,大致得到的原因是当快速双击调用FragmentTransaction.add()方法添加fragmentA,而fragmentA不是每次单独生成的,就会引起这个异常。

上面的内容是网上的解释,不过我认为是因为同一个Fragment被add两次导致的错误,但是奇怪的是我在加载这个Fragment的时候已经做了是否add的判断,为什么还会有这个问题呢。

private void addFragment(FragmentManager fm, Fragment fragment ) {         Log.i( "addFragment", "### " + fragment.getId() + "  " + fragment.isAdded() + "  " + fragment.isHidden() );         if (!fragment.isAdded() ) {             FragmentTransaction ft = fm.beginTransaction();             fm.executePendingTransactions();             ft.add( R.id.main_content, fragment );             ft.commitAllowingStateLoss();         }

通过打印结果发现,第一次切换到FragmentA的时候,FragmentA明明已经add了,但是isAdded()依然显示false

addFragment: ###1 2131755357  false true
addFragment: ###2 2131755357  false true
addFragment: ###3 2131755357  false true
addFragment: ###4 2131755357  false true

第二次切换到相同FragmentA的时候isAdded()就显示为true了

addFragment: ###1 2131755357  true true
addFragment: ###2 2131755357  true true
addFragment: ###3 2131755357  true true
addFragment: ###4 2131755357  true true

在不断快速切换不同的Fragment的时候,isAdded()偶尔会显示false,就因为isAdded()显示了false,那么 ft.add( R.id.main_content, fragment )就会再次执行一次,就会报错,说明通过isAdded()这个方法判断Fragment是否被add可能并不准确。

方法

解决方法就是每次add的时候加上一个tag,然后不仅要通过isAdded()判断Fragment是否add,还要通过FragmentManager.findFragmentByTag(tag)获取Fragment,然后判断此Fragment是否为null。

 case R.id.home_tab_a:         hideAllFragment( fm );         addFragment( fm, fragmentA, "A" );         showFragment( fm, fragmentA );   break;  case R.id.home_tab_b:         hideAllFragment( fm );         addFragment( fm, fragmentB, "B" );         showFragment( fm, fragmentB );   break;  case R.id.home_tab_c:         hideAllFragment( fm );         addFragment( fm, fragmentC, "C" );         showFragment( fm, fragmentC );   break;

影藏所有的Fragment

 private void hideAllFragment(FragmentManager fm) {         FragmentTransaction ft = fm.beginTransaction();         if (!shijianFragment.isHidden())             ft.hide( fragmentA );         if (!riliFragment.isHidden())             ft.hide( fragmentB );         if (!gongjuFragment.isHidden()) {             ft.hide( fragmentC );         }         ft.commitAllowingStateLoss();     }

通过isAdded()判断Fragment是否add,同时通过tag获取Fragment,判断Fragment是否为空,双重判断

   private void addFragment(FragmentManager fm, Fragment fragment, String tag) {         if (!fragment.isAdded()&&null == fm.findFragmentByTag( tag )) {             FragmentTransaction ft = fm.beginTransaction();             fm.executePendingTransactions();             ft.add( R.id.main_content, fragment, tag );             ft.commitAllowingStateLoss();         }     }

显示Fragment

 private void showFragment(FragmentManager fm, Fragment fragment) {         FragmentTransaction ft = fm.beginTransaction();         ft.show( fragment );         ft.commitAllowingStateLoss();     } java.lang.IllegalStateException: Fragment already added 异常处理

10-15 15:52:00.094 3808 3808 E AndroidRuntime: FATAL EXCEPTION: main
10-15 15:52:00.094 3808 3808 E AndroidRuntime: Process: com.xxxx.xxx, PID: 3808
10-15 15:52:00.094 3808 3808 E AndroidRuntime: java.lang.IllegalStateException: Fragment already added
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at androidx.fragment.app.Fragment.setInitialSavedState(Fragment.java:679)
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at androidx.viewpager2.adapter.FragmentStateAdapter.ensureFragment(FragmentStateAdapter.java:269)
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at androidx.viewpager2.adapter.FragmentStateAdapter.onBindViewHolder(FragmentStateAdapter.java:175)
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at androidx.viewpager2.adapter.FragmentStateAdapter.onBindViewHolder(FragmentStateAdapter.java:67)
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at androidx.recyclerview.widget.RecyclerViewA d a p t e r . o n B i n d V i e w H o l d e r ( R e c y c l e r V i e w . j a v a : 7065 ) 10 − 1515 : 52 : 00.09438083808 E A n d r o i d R u n t i m e : a t a n d r o i d x . r e c y c l e r v i e w . w i d g e t . R e c y c l e r V i e w Adapter.onBindViewHolder(RecyclerView.java:7065) 10-15 15:52:00.094 3808 3808 E AndroidRuntime: at androidx.recyclerview.widget.RecyclerViewAdapter.onBindViewHolder(RecyclerView.java:7065)10−1515:52:00.09438083808EAndroidRuntime:atandroidx.recyclerview.widget.RecyclerViewAdapter.bindViewHolder(RecyclerView.java:7107)
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at androidx.recyclerview.widget.RecyclerViewR e c y c l e r . t r y B i n d V i e w H o l d e r B y D e a d l i n e ( R e c y c l e r V i e w . j a v a : 6012 ) 10 − 1515 : 52 : 00.09438083808 E A n d r o i d R u n t i m e : a t a n d r o i d x . r e c y c l e r v i e w . w i d g e t . R e c y c l e r V i e w Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6012) 10-15 15:52:00.094 3808 3808 E AndroidRuntime: at androidx.recyclerview.widget.RecyclerViewRecycler.tryBindViewHolderByDeadline(RecyclerView.java:6012)10−1515:52:00.09438083808EAndroidRuntime:atandroidx.recyclerview.widget.RecyclerViewRecycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6279)
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at androidx.recyclerview.widget.GapWorker.prefetchPositionWithDeadline(GapWorker.java:288)
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at androidx.recyclerview.widget.GapWorker.flushTaskWithDeadline(GapWorker.java:345)
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at androidx.recyclerview.widget.GapWorker.flushTasksWithDeadline(GapWorker.java:361)
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at androidx.recyclerview.widget.GapWorker.prefetch(GapWorker.java:368)
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at androidx.recyclerview.widget.GapWorker.run(GapWorker.java:399)
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:755)
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95)
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at android.os.Looper.loop(Looper.java:154)
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6141)
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:913)
10-15 15:52:00.094 3808 3808 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:803)

报错AndroidRuntime: at androidx.fragment.app.Fragment.setInitialSavedState(Fragment.java:679)

这个错误是我从 fragment A 切换到 fragment B ,fragment B再切换到 fragment C 中,再切换到 fragment B中, fragment B 里面 使用了ViewPager2 + FragmentStateAdapter + RadioButton切换主题,问题就出在我使用的ViewPager2 + FragmentStateAdapter这里。

每次我在多个fragmentA,B,C之间多次切换后,切换到fragment B,点击 radioButton 通知ViewPager2 切换 fragment的主题时,使用方法viewPager2.setCurrentItem(index);,就报上面的错误。

我在想,是否是滑动效果的问题,于是 用viewPager2.setCurrentItem(index,false);然后,由于viewpager2 里面的fragment 里面有recycleviewer ,把viewpager2 的宽高 固定 ,问题解决。

小结一下

1、viewPager2.setCurrentItem(index)改成viewPager2.setCurrentItem(index,false);

2、viewPager2 在布局文件里面把宽高 固定。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持易知道(ezd.cc)。

推荐阅读