1

I navigate to a Fragment, when I press an element in my list and quickly press back I get this error, I dont know the exact line because it does not tell me where it happends, but I suspect is in my onCreateView

My code

override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        if (rootView == null) {
            rootView = inflater.inflate(R.layout.landing_fragment, container, false)
            fetchShops(location)
            setupRecyclerView(rootView!!)
        }
        return rootView
    }



 private fun setupRecyclerView(rootView: View) {
        rootView.landing_rv.layoutManager = LinearLayoutManager(requireContext())
        rootView.landing_rv.addItemDecoration(
            DividerItemDecoration(
                requireActivity(),
                LinearLayoutManager.VERTICAL
            )
        )
        rootView.landing_rv.adapter = landingAdapter
    }

The error that the logcat throws is simply

java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
        at android.view.ViewGroup.addViewInner(ViewGroup.java:5038)
        at android.view.ViewGroup.addView(ViewGroup.java:4869)
        at androidx.fragment.app.FragmentContainerView.addView(FragmentContainerView.java:280)
        at android.view.ViewGroup.addView(ViewGroup.java:4809)
        at android.view.ViewGroup.addView(ViewGroup.java:4782)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:326)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
        at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2224)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1997)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849)
        at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:201)
        at android.app.ActivityThread.main(ActivityThread.java:6806)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)

I use the above check for rootview because I create just one instance of that fragment to prevent my viewModel (fetchShops) to fire twice

SNM
  • 5,625
  • 9
  • 28
  • 77
  • You should always be returning a new `View` instance from `onCreateView()`. Don't try to cache `rootView` like that. – Mike M. May 11 '20 at 20:17
  • I'm doing this to prevent recreating the fragment @MikeM. , is there a better way to save the state and not creating again the view ? – SNM May 12 '20 at 17:45
  • Check @MikeM. : https://stackoverflow.com/questions/54581071/fragments-destroyed-recreated-with-jetpacks-android-navigation-components – SNM May 12 '20 at 17:51
  • That doesn't prevent recreating the `Fragment`; just its `View`, which shouldn't really be a huge bottleneck, anyway. Also, it's rather hacky, regardless of who recommended it. Remove that, temporarily at least, and run your test. If that is the issue, well, you see why it's hacky, then. :-) – Mike M. May 12 '20 at 22:31

1 Answers1

0

How are you spawning your fragment? Something you can try is adding the fragment to the backstack and having some custom back button handling in your parent activity. That way, your fragment's onCreate only gets called once, when it is added. Then within your fragment, move the fetchShops(location) stuff to onCreate. Here's a minimal example:

// MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    supportFragmentManager.beginTransaction().apply {
        add(R.id.frag_container, FragA())
        commit()
    }

override fun onBackPressed() {
    val fragCount = supportFragmentManager.backStackEntryCount

    if (fragCount == 0) {
        super.onBackPressed()
    }
    else {
        supportFragmentManager.popBackStack()
    }
}
// FragA.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    fetchShops(location)
}

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    return inflater.inflate(R.layout.fragment_fraga, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    next_btn.setOnClickListener {
        // Go to frag B.
        requireActivity().supportFragmentManager.beginTransaction().apply {
            replace(R.id.frag_container, FragB())
            addToBackStack(null)
            commit()
        }
    }
}

Hope this helps!

Chase Farmer
  • 113
  • 9