Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DialogCollator destroys/rebuild instead of dismiss/show #1211

Merged
merged 1 commit into from
Jul 31, 2024

Conversation

rjrjr
Copy link
Contributor

@rjrjr rjrjr commented Jul 20, 2024

When DialogCollator has to reorder, it did so by calling Dialog.dismiss() and Dialog.show(). #1213 fixed a problem that caused for ComposeView, but that fix is undone by Compose 1.6.8. @vumngoc dug in to see why and discovered:

The onClick in Modifier.clickable is passed all the way down to pointerInputHandler in SuspendingPointerInputModifierNodeImpl (when the screen is responsive, you should see pointerInputHandler() being called in SuspendingPointerInputModifierNodeImpl#onPointerEvent).

After shuffling the overlays, even though the ClickableNode is found and SuspendingPointerInputModifierNodeImpl#onPointerEvent is called, pointerInputHandler() is never called because the pointerInputJob in SuspendingPointerInputModifierNodeImpl was launched from a canceled coroutineScope. Tracking down that coroutineScope shows that it was canceled when DialogCollator calls Dialog.dismiss -> onViewDetachedFromWindow -> Recomposer.cancel(). So it makes sense why destroying/rebuilding instead of dismissing and reusing the dialog fixes this issue.

Still need to put together a non-workflow repro sample and submit a bug to the Compose team, but this unblocks our move to Compose 1.6.8 in the meantime.

@rjrjr rjrjr requested review from zach-klippenstein and a team as code owners July 20, 2024 01:55
@rjrjr rjrjr force-pushed the ray/dialogamageddon branch 2 times, most recently from 2b8ee77 to 9c847a0 Compare July 22, 2024 23:48
@rjrjr
Copy link
Contributor Author

rjrjr commented Jul 23, 2024

So this is now very, very green, but I'm really torn about whether it's a good idea. On the one hand, I'm tired of obscure bug hunts that boil down to "oh this view is bad about handling being attached to a window more than once." On the other hand, relying on view code to use view state correctly in order to smoothly be reordered doesn't seem great either -- although at least they already have to do that for config change.

Going to try harder to understand why ComposeView is being a jerk. Best case our glue is dumb and can be fixed. Worst case we file a bug against the Compose team and mere this.

Once again, thank you @zach-klippenstein for all these wonderful unit tests!

cc @wardellbagby

@rjrjr rjrjr force-pushed the ray/dialogamageddon branch from 9c847a0 to a14ab07 Compare July 23, 2024 17:46
@rjrjr
Copy link
Contributor Author

rjrjr commented Jul 23, 2024

Initial testing reveals:

  • Default ViewCompositionStrategy.Default does not handle re-showing a dialog
  • Both DisposeOnViewTreeLifecycleDestroyed and DisposeOnDetachedFromWindow fix that problem, which is a pleasant surprise because they didn't do so when I changed ScreenComposableFactory.asViewFactory() to use them

@rjrjr
Copy link
Contributor Author

rjrjr commented Jul 23, 2024

Initial testing reveals:

  • Default ViewCompositionStrategy.Default does not handle re-showing a dialog
  • Both DisposeOnViewTreeLifecycleDestroyed and DisposeOnDetachedFromWindow fix that problem, which is a pleasant surprise because they didn't do so when I changed ScreenComposableFactory.asViewFactory() to use them

Actually, I wasn't re-showing all the dialogs in that first test. Fixing that reveals that DisposeOnDetachedFromWindow does not work, which makes a lot of sense. Only DisposeOnViewTreeLifecycleDestroyed tames ComposeView in this situation, which is what I expected.

Testing with ScreenComposableFactory.asViewFactory() as-is on today's main branch confirms the problem. Changing that to use DisposeOnViewTreeLifecycleDestroyed fixes it!

So: why didn't that fix do the job for us in production?

@rjrjr
Copy link
Contributor Author

rjrjr commented Jul 24, 2024

#1212 (improved testing), #1213 (change ComposeView strategy) spin off of this

@rjrjr rjrjr force-pushed the ray/dialogamageddon branch from a14ab07 to 2399303 Compare July 31, 2024 00:53
@rjrjr rjrjr requested a review from a team as a code owner July 31, 2024 00:53
@rjrjr rjrjr changed the base branch from main to ray/lifecycle-based-ComposeView-strategy July 31, 2024 00:53
@rjrjr
Copy link
Contributor Author

rjrjr commented Jul 31, 2024

Updated the commit message to explain why we're going to go ahead and merge this after all. tl;dr: Compose 1.6.8 breaks what is fixed by #1213

@rjrjr rjrjr force-pushed the ray/dialogamageddon branch from 67e5f5c to 66c65e9 Compare July 31, 2024 01:10
Base automatically changed from ray/lifecycle-based-ComposeView-strategy to main July 31, 2024 22:47
@rjrjr rjrjr force-pushed the ray/dialogamageddon branch from be4481a to 497496e Compare July 31, 2024 22:50
Copy link
Collaborator

@wardellbagby wardellbagby left a comment

Choose a reason for hiding this comment

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

I understand it at a high-level but I'm trusting you with the ViewState stuff 'cause that's outta my wheelhouse!

@rjrjr rjrjr enabled auto-merge July 31, 2024 23:02
@rjrjr
Copy link
Contributor Author

rjrjr commented Jul 31, 2024

I understand it at a high-level but I'm trusting you with the ViewState stuff 'cause that's outta my wheelhouse!

Fair. The good news is that I realized I need to fix these because various tests broke. I'm pretty confident.

When `DialogCollator` has to reorder, it did so by calling `Dialog.dismiss()` and `Dialog.show()`. #1213 fixed a problem that caused for `ComposeView`, but that fix is undone by Compose 1.6.8. @vumngoc dug in to see why and discovered:

> The `onClick` in `Modifier.clickable` is passed all the way down to `pointerInputHandler` in `SuspendingPointerInputModifierNodeImpl` (when the screen is responsive, you should see `pointerInputHandler()` being called in `SuspendingPointerInputModifierNodeImpl#onPointerEvent`).
>
> After shuffling the overlays, even though the `ClickableNode` is found and `SuspendingPointerInputModifierNodeImpl#onPointerEvent` is called, `pointerInputHandler()` is never called  because the `pointerInputJob` in `SuspendingPointerInputModifierNodeImpl` was launched from a canceled coroutineScope. Tracking down that coroutineScope shows that it was canceled when `DialogCollator` calls `Dialog.dismiss` -> `onViewDetachedFromWindow`  -> `Recomposer.cancel()`. So it makes sense why destroying/rebuilding instead of dismissing and reusing the dialog fixes this issue.

Still need to put together a non-workflow repro sample and submit a bug to the Compose team, but this unblocks our move to Compose 1.6.8 in the meantime.
@rjrjr rjrjr force-pushed the ray/dialogamageddon branch from 497496e to fae88ea Compare July 31, 2024 23:04
@rjrjr rjrjr merged commit c4f52b1 into main Jul 31, 2024
31 checks passed
@rjrjr rjrjr deleted the ray/dialogamageddon branch July 31, 2024 23:23
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.

2 participants