I have a Single Activity App with a bottombar. Each tab of the bottombar is a fragment which acts as a container and presents several childfragments. Only on Android versions <21 the app crashes with the following stacktrace:
Process: de.name.dev, PID: 5262
java.lang.IllegalStateException: Activity has been destroyed
at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1345)
at android.app.BackStackRecord.commitInternal(BackStackRecord.java:597)
at android.app.BackStackRecord.commit(BackStackRecord.java:575)
at de.xxxxxx.more.MoreFragment.onViewCreated(MoreFragment.kt:30)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:904)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1062)
at android.app.BackStackRecord.run(BackStackRecord.java:684)
at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1447)
at android.app.FragmentManagerImpl$1.run(FragmentManager.java:443)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)
Our ContainerFragment looks like this:
class MoreFragment : KodeinFragment(), MoreOpenWebViewListener {
private val settingsFragment by lazy {
SettingsFragment(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.fragment_more, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
childFragmentManager.beginTransaction()
.add(R.id.more_container, settingsFragment)
.commit()
}
...
In onViewCreated the container adds the fragment to show to its childfragmentManager.
If navigated between tabs the fragment will get destroyed and recreated.
On the 2nd time you come to the .commit() it crashes with above stacktrace.
The MoreFragment is instantiated in another ContainerFragment which is the TabBarFragment:
class TabBarFragment : KodeinFragment() {
private val sessionStore: SessionStore by instance()
private val fragment1 by lazy { Fragment1() }
private val moreFragment by lazy { MoreFragment() }
private val fragment2 by lazy { fragment2.newFragment2(sessionStore.data) }
var currentTabFragment: Fragment? = null
private set
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
childFragmentManager
.beginTransaction()
.add(R.id.fragment_container, contractsFragment)
.commit()
bottomBar.selectTabAtPosition(0)
bottomBar.setOnTabSelectListener { tabId ->
when (tabId) {
R.id.tab1 -> replaceFragment(fragment1)
R.id.tab2 -> replaceFragment(fragment2)
R.id.tab_settings -> replaceFragment(moreFragment)
}
}
ViewCompat.setElevation(bottomBar, 8.0f * resources.displayMetrics.density)
}
private fun replaceFragment(fragment: Fragment) {
childFragmentManager.beginTransaction().replace(R.id.fragment_container, fragment).commit()
currentTabFragment = fragment
}
}
Any Idea whats happening?
Found a solution here: Getting the error "Java.lang.IllegalStateException Activity has been destroyed" when using tabs with ViewPager Its a known bug in android.
You have to override the onDetach() in the Fragments that use the childFragmentManager and set its reference to null.
override fun onDetach() {
super.onDetach()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
try {
val childFragmentManager = Fragment::class.java!!.getDeclaredField("mChildFragmentManager")
childFragmentManager.setAccessible(true)
childFragmentManager.set(this, null)
} catch (e: NoSuchFieldException) {
throw RuntimeException(e)
} catch (e: IllegalAccessException) {
throw RuntimeException(e)
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With