-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Fixing crash caused by Scrollable.animateTo interrupting HoldActivity before proper disposal is possible #37267
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
Conversation
packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart
Outdated
Show resolved
Hide resolved
chunhtai
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart
Outdated
Show resolved
Hide resolved
|
I just tried to reproduce this with the code given in #14452 and I am seeing a slightly different chain of events to get to the crash: It doesn't seem to be the user gesture that's interrupted by the automated animation that's causing the crash. Instead, it seem to be the other way around: The animation is interrupting an "in-progress" user gesture and that causes the crash. (Maybe that's what was meant by the PR description and I misunderstood?) Here is the sequence of events I am seeing:
Is this another sequence that leads to a crash? Or is that what you meant? |
|
Also, I am not convinced that this actually fixes the root cause of the crash. It removes a notification, that is used in user-defined code to trigger the animation. The animation could also be triggered via other means from user code (e.g. a timer that just happens to fire in the right moment) and that would still crash... |
No, the timer will not cause the crash, it has to happen at the exact moment at this line.
After calling position.hold(_disposeHold) before returning the hold handle. This is a sync function except it trigger a a notification in the middle which allow other action to interrupt before the hold handle returns. I think the other way to fix this is not letting automatic action interrupt user action, but we still want to fix hold action trigger an errant notification. That is why I think this is the right fix since i cannot think of any other way automatic action can interrupt user action if we fix the errant notification. |
Yes that is what i observed as well. |
Yes. I also agree. Very well explained. :) I'm going to see about addressing the notification error, since I think we all agree that a HoldActivity does not constitute that the ScrollDirection is idle. As for other cases where an animation may interrupt a user gesture, I will see about creating a reproduction of the timer case you recommended @goderbauer and see if it causes a crash. |
|
I created a gist that triggers the animation after a time delay instead of after a notification. Available here: https://gist.github.com/Piinks/955c449d2764e4591b574859c7a0395f If you hold (don't drag) after triggering the future that delays the animation, the |
packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart
Outdated
Show resolved
Hide resolved
|
@chunhtai Ah, I see. Looking at the line you pointed out:
The underlying problem is that We also dispatch a scrollendnotification when the hold starts: flutter/packages/flutter/lib/src/widgets/scroll_position.dart Lines 638 to 639 in 4ccd811
What if you trigger the animation from that one? |
Codecov Report
@@ Coverage Diff @@
## master #37267 +/- ##
==========================================
+ Coverage 55.22% 56.04% +0.82%
==========================================
Files 193 193
Lines 18172 18141 -31
==========================================
+ Hits 10036 10168 +132
+ Misses 8136 7973 -163
Continue to review full report at Codecov.
|
Yes, I think that is another corner case. it seems like we should somehow know how to reset _hold when it gets interrupted before 'hold' returns. |
Thank you for the feedback. I will look into this corner case as well and see if adding a reset _hold type method would be a better approach to fixing this crash. I will close this for now while I investigate further. |
|
That being said, I am still thinking this pr is worth fixing as hold activity should not be consider as idle according to the documentation
|
|
I've added a reset-like path for when an animation is fired before the hold can be disposed of properly. A similar functionality existed in the class for keeping track of |
| delegate: this, | ||
| onHoldCanceled: holdCancelCallback, | ||
| ); | ||
| _currentHold = holdActivity; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we assert that _currentHold is null to ensure we are not overwriting a hold?
| // the [ScrollableState] has not yet received the handle to the | ||
| // [HoldActivity], it will not be properly disposed of in [beginActivity]. | ||
| // Therefore, we dispose of any active hold here. | ||
| if (_currentHold != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would jumpTo have the same issue?
| // the [ScrollableState] has not yet received the handle to the | ||
| // [HoldActivity], it will not be properly disposed of in [beginActivity]. | ||
| // Therefore, we dispose of any active hold here. | ||
| if (_currentHold != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And wouldn't we also have a similar problem when there is an ongoing drag? (e.g. when an animation triggers based on the onScrollStartNotification before we had a chance to get the handle for the drag)
|
After offline chat with @goderbauer, the problem here lies in the potential gap that is created when a scroll notification is used to initiate an activity. It leaves open a small window where the activity can interrupt a currently executing one since scroll notifications are dispatched at different points in an activity's execution. |
Description
This PR fixes a crash caused by an animating
ScrollPositionWithSingleContextinterrupting an activeHoldActivitybefore the handle has been returned to theScrollable. When this happens, theHoldActivitycannot be disposed of properly. This change keeps track of the_currentHoldfrom within theScrollPositionWithSingleConextso that is may be disposed of in this case, effectively resetting the ScrollActivity.Related Issues
Fixes #14452
Fixes #11433
Tests
I added the following tests:
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]). This will ensure a smooth and quick review process.///).flutter analyze --flutter-repo) does not report any problems on my PR.Breaking Change
Does your PR require Flutter developers to manually update their apps to accommodate your change?