From 3415b44273c64cf5ec165a6f0cf6086fe4aa5f75 Mon Sep 17 00:00:00 2001 From: PavloNetrebchuk Date: Thu, 31 Jul 2025 17:54:35 +0300 Subject: [PATCH] fix: MainFragment pager memory leaks --- .../main/java/org/openedx/app/MainFragment.kt | 46 +++++++++---------- .../core/adapter/NavigationFragmentAdapter.kt | 10 ++-- .../learn/presentation/LearnFragment.kt | 4 +- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/org/openedx/app/MainFragment.kt b/app/src/main/java/org/openedx/app/MainFragment.kt index c58ec437f..82092e439 100644 --- a/app/src/main/java/org/openedx/app/MainFragment.kt +++ b/app/src/main/java/org/openedx/app/MainFragment.kt @@ -39,8 +39,6 @@ class MainFragment : Fragment(R.layout.fragment_main) { private val viewModel by viewModel() private val router by inject() - private lateinit var adapter: NavigationFragmentAdapter - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) lifecycle.addObserver(viewModel) @@ -89,26 +87,28 @@ class MainFragment : Fragment(R.layout.fragment_main) { requireArguments().remove(ARG_OPEN_TAB) } - private fun createTabList(openTabArg: String): List> { - val learnFragment = LearnFragment.newInstance( - openTab = if (openTabArg == HomeTab.PROGRAMS.name) { - LearnTab.PROGRAMS.name - } else { - LearnTab.COURSES.name - } - ) + private fun createTabList(openTabArg: String): List Fragment>> { + val learnFragmentFactory = { + LearnFragment.newInstance( + openTab = if (openTabArg == HomeTab.PROGRAMS.name) { + LearnTab.PROGRAMS.name + } else { + LearnTab.COURSES.name + } + ) + } - return mutableListOf>().apply { - add(R.id.fragmentLearn to learnFragment) - add(R.id.fragmentDiscover to viewModel.getDiscoveryFragment) + return mutableListOf Fragment>>().apply { + add(R.id.fragmentLearn to learnFragmentFactory) + add(R.id.fragmentDiscover to { viewModel.getDiscoveryFragment }) if (viewModel.isDownloadsFragmentEnabled) { - add(R.id.fragmentDownloads to DownloadsFragment()) + add(R.id.fragmentDownloads to { DownloadsFragment() }) } - add(R.id.fragmentProfile to ProfileFragment()) + add(R.id.fragmentProfile to { ProfileFragment() }) } } - private fun addMenuItems(menu: Menu, tabList: List>) { + private fun addMenuItems(menu: Menu, tabList: List Fragment>>) { val tabTitles = mapOf( R.id.fragmentLearn to resources.getString(R.string.app_navigation_learn), R.id.fragmentDiscover to resources.getString(R.string.app_navigation_discovery), @@ -128,7 +128,7 @@ class MainFragment : Fragment(R.layout.fragment_main) { } } - private fun setupBottomNavListener(tabList: List>) { + private fun setupBottomNavListener(tabList: List Fragment>>) { val menuIdToIndex = tabList.mapIndexed { index, pair -> pair.first to index }.toMap() binding.bottomNavView.setOnItemSelectedListener { menuItem -> @@ -173,21 +173,21 @@ class MainFragment : Fragment(R.layout.fragment_main) { } else { R.id.fragmentLearn } + HomeTab.PROFILE.name -> R.id.fragmentProfile else -> R.id.fragmentLearn } } - private fun initViewPager(tabList: List>) { + private fun initViewPager(tabList: List Fragment>>) { binding.viewPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL binding.viewPager.offscreenPageLimit = tabList.size - - adapter = NavigationFragmentAdapter(this).apply { - tabList.forEach { (_, fragment) -> - addFragment(fragment) + binding.viewPager.adapter = NavigationFragmentAdapter(this).apply { + tabList.forEach { (_, fragmentFactory) -> + // Use fragment factory to prevent memory leaks + addFragment { fragmentFactory() } } } - binding.viewPager.adapter = adapter binding.viewPager.isUserInputEnabled = false } diff --git a/core/src/main/java/org/openedx/core/adapter/NavigationFragmentAdapter.kt b/core/src/main/java/org/openedx/core/adapter/NavigationFragmentAdapter.kt index 708b43829..f3d210449 100644 --- a/core/src/main/java/org/openedx/core/adapter/NavigationFragmentAdapter.kt +++ b/core/src/main/java/org/openedx/core/adapter/NavigationFragmentAdapter.kt @@ -5,13 +5,13 @@ import androidx.viewpager2.adapter.FragmentStateAdapter class NavigationFragmentAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { - private val fragments = ArrayList() + private val fragmentFactories = ArrayList<() -> Fragment>() - override fun getItemCount(): Int = fragments.size + override fun getItemCount(): Int = fragmentFactories.size - override fun createFragment(position: Int): Fragment = fragments[position] + override fun createFragment(position: Int): Fragment = fragmentFactories[position].invoke() - fun addFragment(fragment: Fragment) { - fragments.add(fragment) + fun addFragment(fragmentFactory: () -> Fragment) { + fragmentFactories.add(fragmentFactory) } } diff --git a/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt b/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt index dd5c0eb34..b7fe74fd0 100644 --- a/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt +++ b/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt @@ -91,8 +91,8 @@ class LearnFragment : Fragment(R.layout.fragment_learn) { binding.viewPager.offscreenPageLimit = 2 adapter = NavigationFragmentAdapter(this).apply { - addFragment(viewModel.getDashboardFragment) - addFragment(viewModel.getProgramFragment) + addFragment { viewModel.getDashboardFragment } + addFragment { viewModel.getProgramFragment } } binding.viewPager.adapter = adapter binding.viewPager.setUserInputEnabled(false)