關(guān)于Fragment?already?added問題的解決方案
Fragment already added問題解決
問題
當(dāng)快速點(diǎn)擊切換不同的Fragment的時候部分手機(jī)的app竟然掛了,
報(bào)出了下面的錯誤 Fragment already added
java.lang.IllegalStateException: Fragment already added: xxxxFragment
上網(wǎng)找了很多,大致得到的原因是當(dāng)快速雙擊調(diào)用FragmentTransaction.add()方法添加fragmentA,而fragmentA不是每次單獨(dú)生成的,就會引起這個異常。
上面的內(nèi)容是網(wǎng)上的解釋,不過我認(rèn)為是因?yàn)橥粋€Fragment被add兩次導(dǎo)致的錯誤,但是奇怪的是我在加載這個Fragment的時候已經(jīng)做了是否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(); ? ? ? ? }
通過打印結(jié)果發(fā)現(xiàn),第一次切換到FragmentA的時候,F(xiàn)ragmentA明明已經(jīng)add了,但是isAdded()依然顯示false
addFragment: ###1 2131755357 false true
addFragment: ###2 2131755357 false true
addFragment: ###3 2131755357 false true
addFragment: ###4 2131755357 false true
第二次切換到相同F(xiàn)ragmentA的時候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,就因?yàn)閕sAdded()顯示了false,那么 ft.add( R.id.main_content, fragment )就會再次執(zhí)行一次,就會報(bào)錯,說明通過isAdded()這個方法判斷Fragment是否被add可能并不準(zhǔn)確。
方法
解決方法就是每次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)
報(bào)錯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,點(diǎn)擊 radioButton 通知ViewPager2 切換 fragment的主題時,使用方法viewPager2.setCurrentItem(index);,就報(bào)上面的錯誤。
我在想,是否是滑動效果的問題,于是 用viewPager2.setCurrentItem(index,false);然后,由于viewpager2 里面的fragment 里面有recycleviewer ,把viewpager2 的寬高 固定 ,問題解決。
小結(jié)一下
1、viewPager2.setCurrentItem(index)改成viewPager2.setCurrentItem(index,false);
2、viewPager2 在布局文件里面把寬高 固定。
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Android實(shí)現(xiàn)新浪微博一鍵分享的實(shí)例代碼
這篇文章主要介紹了Android實(shí)現(xiàn)新浪微博一鍵分享的實(shí)例代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07Android CameraX結(jié)合LibYUV和GPUImage自定義相機(jī)濾鏡
之前使用Camera實(shí)現(xiàn)了一個自定義相機(jī)濾鏡(Android自定義相機(jī)濾鏡 ),但是運(yùn)行起來有點(diǎn)卡頓,這次用Camerax來實(shí)現(xiàn)一樣的效果發(fā)現(xiàn)很流暢,在此記錄一下,也希望能幫到有需要的同學(xué)2021-12-12Android 中倒計(jì)時驗(yàn)證兩種常用方式實(shí)例詳解
這篇文章主要介紹了Android 中倒計(jì)時驗(yàn)證兩種常用方式實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-06-06Flutter學(xué)習(xí)之矢量圖SVG的區(qū)域填色示例詳解
這篇文章主要為大家介紹了Flutter學(xué)習(xí)之矢量圖SVG的區(qū)域填色示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04Android中AndroidStudio&Kotlin安裝到運(yùn)行過程及常見問題匯總
這篇文章主要介紹了Android(AndroidStudio&Kotlin)安裝到運(yùn)行過程及常見問題匯總,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒借鑒價值,需要的朋友可以參考下2020-03-03Android實(shí)現(xiàn)屏幕各尺寸的獲取的示例
本篇文章主要介紹了Android實(shí)現(xiàn)屏幕各尺寸的獲取的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-09-09