From 014f9456f6425191d01710256a266ae0bf56854e Mon Sep 17 00:00:00 2001 From: edde746 <86283021+edde746@users.noreply.github.com> Date: Sat, 28 Feb 2026 10:23:28 +0100 Subject: [PATCH] fix: defer view removal to avoid AOSP dispatchWindowVisibilityChanged NPE --- .../com/edde746/plezy/exoplayer/ExoPlayerCore.kt | 14 ++++++-------- .../kotlin/com/edde746/plezy/mpv/MpvPlayerCore.kt | 11 +++++------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/android/app/src/main/kotlin/com/edde746/plezy/exoplayer/ExoPlayerCore.kt b/android/app/src/main/kotlin/com/edde746/plezy/exoplayer/ExoPlayerCore.kt index 27285b1a..3728bf20 100644 --- a/android/app/src/main/kotlin/com/edde746/plezy/exoplayer/ExoPlayerCore.kt +++ b/android/app/src/main/kotlin/com/edde746/plezy/exoplayer/ExoPlayerCore.kt @@ -1390,23 +1390,21 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener { trackSelector = null assHandler = null - surfaceView?.holder?.removeCallback(surfaceCallback) + val cb = surfaceCallback + val sv = surfaceView overlayLayoutListener?.let { listener -> val contentView = activity.findViewById(android.R.id.content) contentView.viewTreeObserver.removeOnGlobalLayoutListener(listener) } overlayLayoutListener = null - // Remove SurfaceView from container synchronously — triggers - // onDetachedFromWindow which properly unregisters PositionUpdateListener - // and releases SurfaceControl before the render thread can access it. + // Defer all view removal to avoid AOSP bug where + // dispatchWindowVisibilityChanged iterates stale children array + // when removeView() runs during an active performTraversals pass. val container = surfaceContainer - surfaceView?.let { container?.removeView(it) } - subtitleView?.let { container?.removeView(it) } - - // Defer empty container removal (plain FrameLayout, no SurfaceControl) val contentView = activity.findViewById(android.R.id.content) contentView.post { + sv?.holder?.removeCallback(cb) container?.let { contentView.removeView(it) } } surfaceContainer = null diff --git a/android/app/src/main/kotlin/com/edde746/plezy/mpv/MpvPlayerCore.kt b/android/app/src/main/kotlin/com/edde746/plezy/mpv/MpvPlayerCore.kt index 13a2f97b..0e894414 100644 --- a/android/app/src/main/kotlin/com/edde746/plezy/mpv/MpvPlayerCore.kt +++ b/android/app/src/main/kotlin/com/edde746/plezy/mpv/MpvPlayerCore.kt @@ -809,15 +809,14 @@ class MpvPlayerCore(private val activity: Activity) : } overlayLayoutListener = null - // Remove SurfaceView synchronously (keep callback so surfaceDestroyed - // fires → MPVLib.detachSurface()), then remove callback after. + // Defer all view removal to avoid AOSP bug where + // dispatchWindowVisibilityChanged iterates stale children array + // when removeView() runs during an active performTraversals pass. + val sv = surfaceView val container = surfaceContainer - surfaceView?.let { container?.removeView(it) } - surfaceView?.holder?.removeCallback(this) - - // Defer empty container removal (plain FrameLayout, no SurfaceControl) val contentView = activity.findViewById(android.R.id.content) contentView.post { + sv?.holder?.removeCallback(this) container?.let { contentView.removeView(it) } } surfaceContainer = null