Ziiiimon
Ziiiimon

Reputation: 101

IllegalStateException: Activity has been destroyed (API level <21)

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?

Upvotes: 3

Views: 527

Answers (1)

Ziiiimon
Ziiiimon

Reputation: 101

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

Upvotes: 1

Related Questions