ui: fix back listener leak

Fix an issue where the OnBackPressedListeners would leak their bound
views once MainFragment's view was destroyed.
This commit is contained in:
Alexander Capehart 2023-06-03 09:24:10 -06:00
parent 736f3ec6b7
commit d49034b664
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47

View file

@ -81,10 +81,10 @@ class MainFragment :
private val playbackModel: PlaybackViewModel by activityViewModels()
private val selectionModel: SelectionViewModel by activityViewModels()
private val detailModel: DetailViewModel by activityViewModels()
private lateinit var sheetBackCallback: SheetBackPressedCallback
private lateinit var detailBackCallback: DetailBackPressedCallback
private lateinit var selectionBackCallback: SelectionBackPressedCallback
private lateinit var exploreBackCallback: ExploreBackPressedCallback
private var sheetBackCallback: SheetBackPressedCallback? = null
private var detailBackCallback: DetailBackPressedCallback? = null
private var selectionBackCallback: SelectionBackPressedCallback? = null
private var exploreBackCallback: ExploreBackPressedCallback? = null
private var lastInsets: WindowInsets? = null
private var elevationNormal = 0f
private var initialNavDestinationChange = true
@ -110,13 +110,17 @@ class MainFragment :
// Currently all back press callbacks are handled in MainFragment, as it's not guaranteed
// that instantiating these callbacks in their respective fragments would result in the
// correct order.
sheetBackCallback =
val sheetBackCallback =
SheetBackPressedCallback(
playbackSheetBehavior = playbackSheetBehavior,
queueSheetBehavior = queueSheetBehavior)
detailBackCallback = DetailBackPressedCallback(detailModel)
selectionBackCallback = SelectionBackPressedCallback(selectionModel)
exploreBackCallback = ExploreBackPressedCallback(binding.exploreNavHost)
playbackSheetBehavior = playbackSheetBehavior,
queueSheetBehavior = queueSheetBehavior)
.also { sheetBackCallback = it }
val detailBackCallback =
DetailBackPressedCallback(detailModel).also { detailBackCallback = it }
val selectionBackCallback =
SelectionBackPressedCallback(selectionModel).also { selectionBackCallback = it }
val exploreBackCallback =
ExploreBackPressedCallback(binding.exploreNavHost).also { exploreBackCallback = it }
// --- UI SETUP ---
val context = requireActivity()
@ -202,6 +206,14 @@ class MainFragment :
binding.playbackSheet.viewTreeObserver.removeOnPreDrawListener(this)
}
override fun onDestroyBinding(binding: FragmentMainBinding) {
super.onDestroyBinding(binding)
sheetBackCallback = null
detailBackCallback = null
selectionBackCallback = null
exploreBackCallback = null
}
override fun onPreDraw(): Boolean {
// We overload CoordinatorLayout far too much to rely on any of it's typical
// listener functionality. Just update all transitions before every draw. Should
@ -287,7 +299,8 @@ class MainFragment :
// Since the navigation listener is also reliant on the bottom sheets, we must also update
// it every frame.
sheetBackCallback.invalidateEnabled()
requireNotNull(sheetBackCallback) { "SheetBackPressedCallback was not available" }
.invalidateEnabled()
return true
}
@ -300,7 +313,8 @@ class MainFragment :
// Drop the initial call by NavController that simply provides us with the current
// destination. This would cause the selection state to be lost every time the device
// rotates.
exploreBackCallback.invalidateEnabled()
requireNotNull(exploreBackCallback) { "ExploreBackPressedCallback was not available" }
.invalidateEnabled()
if (!initialNavDestinationChange) {
initialNavDestinationChange = true
return