Rainmaker
Rainmaker

Reputation: 11100

Compose NavController is leaking

I add ComposeView straight to activity root (this is how I launch ModalBottomsheetLayout from xml view, example below is simplified but still reproducible) Here is the whole fragment of reproducible example:

class TestFragment : Fragment() {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        return ComposeView(requireContext()).apply {
            setViewCompositionStrategy(
                ViewCompositionStrategy
                    .DisposeOnViewTreeLifecycleDestroyed,
            )
            setContent {
                LazyColumn(
                    verticalArrangement = Arrangement.Top,
                    horizontalAlignment = Alignment.CenterHorizontally,
                ) {
                    item {
                        ListItem(title = "launchBS") { launchBS() }
                    }
                    item {
                        ListItem(title = "closeBS") {
                            activity
                                ?.findViewById<ViewGroup>(android.R.id.content)
                                ?.let { viewGroup ->
                                    val viewToRemove = viewGroup.findViewWithTag<ComposeView>(BS_VIEW_TAG)
                                    viewToRemove?.disposeComposition()
                                    viewGroup.removeView(viewToRemove)
                                }
                        }
                    }
                }
            }
        }
    }

    private fun launchBS() {
        activity
            ?.findViewById<ViewGroup>(android.R.id.content)
            ?.let { viewGroup ->
                val composeView = ComposeView(viewGroup.context).apply {
                    setViewCompositionStrategy(
                            ViewCompositionStrategy.DisposeOnDetachedFromWindow
                        )
                    setContent {
                        val navController = rememberNavController()
                        NavHost(navController, startDestination = DEFAULT_DESTINATION) {
                            composable(DEFAULT_DESTINATION) {
                                Text(text = "COMPOSE BOTTOMSHEET IS DISPLAYING")
                            }
                        }
                        DisposableEffect(Unit) {
                            onDispose {
                                navController.popBackStack(DEFAULT_DESTINATION, true)
                            }
                        }
                    }
                    tag = BS_VIEW_TAG
                }
                viewGroup.addView(
                    composeView
                )
            }
    } 
}

Explanation:

  1. when I click "launchBS" - ComposeView is added to activity, which contains NavHost for future viewModel scoping etc.
  2. when I click "closeBS" - I pop NavController backstack and remove ComposeView from activity.

The problem:

  1. when ComposeView is removed - NavHostController is still allocated in memory. When I open/close 5 times for example, I have 5 allocations of it. Deallocation happens only when Activity is Destroyed.

Questions:

  1. Is this intended behaviour of NahHost / NavController?
  2. Is there a fix or workaround to destroy NavController and related NavHost allocations even though activity is still active?

Here is the reproducible example https://github.com/dkachan1941/Android-NavHost-Leak-Demo

enter image description here enter image description here

Upvotes: 2

Views: 174

Answers (0)

Related Questions