fix(android): SurfaceControl crash on player dispose

This commit is contained in:
edde746
2026-02-23 05:28:10 +01:00
parent 1860a1cea6
commit 6916b386eb
2 changed files with 19 additions and 7 deletions
@@ -146,6 +146,7 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
private fun ensureFlutterOverlayOnTop() {
val contentView = activity.findViewById<ViewGroup>(android.R.id.content)
contentView.post {
if (!isInitialized) return@post
var flutterContainer: ViewGroup? = null
for (i in 0 until contentView.childCount) {
@@ -1275,14 +1276,19 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener {
val contentView = activity.findViewById<ViewGroup>(android.R.id.content)
contentView.viewTreeObserver.removeOnGlobalLayoutListener(listener)
}
overlayLayoutListener = null
// Post view removal to next frame to avoid SurfaceControl race on render thread
val contentView = activity.findViewById<ViewGroup>(android.R.id.content)
// Remove SurfaceView from container synchronously — triggers
// onDetachedFromWindow which properly unregisters PositionUpdateListener
// and releases SurfaceControl before the render thread can access it.
val container = surfaceContainer
val subtitle = subtitleView
surfaceView?.let { container?.removeView(it) }
subtitleView?.let { container?.removeView(it) }
// Defer empty container removal (plain FrameLayout, no SurfaceControl)
val contentView = activity.findViewById<ViewGroup>(android.R.id.content)
contentView.post {
container?.let { contentView.removeView(it) }
subtitle?.let { contentView.removeView(it) }
}
surfaceContainer = null
surfaceView = null
@@ -135,6 +135,7 @@ class MpvPlayerCore(private val activity: Activity) :
private fun ensureFlutterOverlayOnTop() {
val contentView = activity.findViewById<ViewGroup>(android.R.id.content)
contentView.post {
if (!isInitialized) return@post
var flutterContainer: ViewGroup? = null
// First pass: look for FlutterView by name (debug builds)
@@ -717,15 +718,20 @@ class MpvPlayerCore(private val activity: Activity) :
MPVLib.removeObserver(this)
MPVLib.removeLogObserver(this)
surfaceView?.holder?.removeCallback(this)
overlayLayoutListener?.let { listener ->
val contentView = activity.findViewById<ViewGroup>(android.R.id.content)
contentView.viewTreeObserver.removeOnGlobalLayoutListener(listener)
}
overlayLayoutListener = null
// Post view removal to next frame to avoid SurfaceControl race on render thread
val contentView = activity.findViewById<ViewGroup>(android.R.id.content)
// Remove SurfaceView synchronously (keep callback so surfaceDestroyed
// fires → MPVLib.detachSurface()), then remove callback after.
val container = surfaceContainer
surfaceView?.let { container?.removeView(it) }
surfaceView?.holder?.removeCallback(this)
// Defer empty container removal (plain FrameLayout, no SurfaceControl)
val contentView = activity.findViewById<ViewGroup>(android.R.id.content)
contentView.post {
container?.let { contentView.removeView(it) }
}