Skip to content

fix(android): don't re-acquire a disposed Rive file on view re-attach#319

Open
mfazekas wants to merge 3 commits into
mainfrom
fix/android-disposed-file-reattach
Open

fix(android): don't re-acquire a disposed Rive file on view re-attach#319
mfazekas wants to merge 3 commits into
mainfrom
fix/android-disposed-file-reattach

Conversation

@mfazekas

@mfazekas mfazekas commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Fixes a production crash: after a RiveView is dropped, dispose() releases the controller (which releases its File), but rendererAttributes.resource still caches a ResourceRiveFile pointing at the now-disposed file. If the Android view is later attached to a window again (e.g. Fabric view recycling), RiveAnimationView.onAttachedToWindow reloads that stale resource and throws Cannot acquire a disposed object in RiveFileController.setFile -> NativeObject.acquire.

dispose() now nulls rendererAttributes.resource before releasing the controller (mirrors RiveAnimationView.saveControllerState()), and onAttachedToWindow drops a cached ResourceRiveFile whose file has no cpp object before calling super.

Reproduced and verified with the included Disposed File Re-attach reproducer page. The re-attach itself is driven by rive-debug-utils, a new private workspace package with an Android-only Nitro hybrid object that captures the dropped Android view and re-attaches it the way view recycling would; it autolinks into all three example apps. The reproducer crashes with the exact production stack before the fix and passes after.

Same fix as #318, which targets the feat/use-viewmodel-instance-async branch (its android/src/legacy variant).

mfazekas added 3 commits July 6, 2026 07:39
After a RiveView is dropped, dispose() releases the controller (which
releases its File), but rendererAttributes.resource still caches a
ResourceRiveFile pointing at the now-disposed File. If the Android view
is later attached to a window again (e.g. Fabric view recycling),
RiveAnimationView.onAttachedToWindow reloads that stale resource and
crashes with "Cannot acquire a disposed object" in
RiveFileController.setFile -> NativeObject.acquire.

Null rendererAttributes.resource in dispose() (mirrors
RiveAnimationView.saveControllerState()) and drop a stale dead-file
resource in onAttachedToWindow before calling super.

Reproduced and verified with the new Disposed File Re-attach reproducer
page, backed by a dev-only RiveViewReattach native module in the example
app that re-attaches the dropped Android view like view recycling would:
FAIL (crash) before the fix, PASS after.
…ive helper

The reproducer page is reachable from the Expo examples via the shared
PagesList, but the RiveViewReattach helper only exists in the bare
example app — pressing Run there would throw.
…tils nitro package

Private workspace package (not published) with an Android-only Nitro
HybridObject exposing captureView/reattachCapturedView/releaseCapturedView.
Autolinked into all three example apps (bare + both Expo apps via prebuild),
replacing the bare-example-only RiveViewReattach bridge module, so the
Disposed File Re-attach reproducer works everywhere.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit

ktlint

🚫 [ktlint] standard:wrapping reported by reviewdog 🐶
Missing newline after ","


🚫 [ktlint] standard:wrapping reported by reviewdog 🐶
Missing newline before ")"


🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Argument should be on a separate line (unless all arguments can fit a single line)


🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Missing newline before ")"

@@ -0,0 +1,63 @@
///

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:comment-spacing reported by reviewdog 🐶
Missing space after //

@@ -0,0 +1,63 @@
///
/// HybridDebugUtilsSpec.kt

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:comment-spacing reported by reviewdog 🐶
Missing space after //

@@ -0,0 +1,63 @@
///
/// HybridDebugUtilsSpec.kt
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:comment-spacing reported by reviewdog 🐶
Missing space after //

///
/// HybridDebugUtilsSpec.kt
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
/// https://github.com/mrousavy/nitro

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:comment-spacing reported by reviewdog 🐶
Missing space after //

/// HybridDebugUtilsSpec.kt
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
/// https://github.com/mrousavy/nitro
/// Copyright © Marc Rousavy @ Margelo

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:comment-spacing reported by reviewdog 🐶
Missing space after //

companion object {
private const val TAG = "RiveDebugUtilsOnLoad"
private var didLoad = false
/**

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:spacing-between-declarations-with-comments reported by reviewdog 🐶
Declarations and declarations with comments should have an empty space between.

Log.i(TAG, "Successfully loaded RiveDebugUtils C++ library!")
didLoad = true
} catch (e: Error) {
Log.e(TAG, "Failed to load RiveDebugUtils C++ library! Is it properly installed and linked? " +

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:wrapping reported by reviewdog 🐶
Missing newline after "("

Log.i(TAG, "Successfully loaded RiveDebugUtils C++ library!")
didLoad = true
} catch (e: Error) {
Log.e(TAG, "Failed to load RiveDebugUtils C++ library! Is it properly installed and linked? " +

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Argument should be on a separate line (unless all arguments can fit a single line)

Log.i(TAG, "Successfully loaded RiveDebugUtils C++ library!")
didLoad = true
} catch (e: Error) {
Log.e(TAG, "Failed to load RiveDebugUtils C++ library! Is it properly installed and linked? " +

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:wrapping reported by reviewdog 🐶
Missing newline after ","

Log.i(TAG, "Successfully loaded RiveDebugUtils C++ library!")
didLoad = true
} catch (e: Error) {
Log.e(TAG, "Failed to load RiveDebugUtils C++ library! Is it properly installed and linked? " +

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Argument should be on a separate line (unless all arguments can fit a single line)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant