fix guard ScrollController with positions check#4029
Conversation
There was a problem hiding this comment.
Code Review
This review identified a potential memory leak due to an undisposed _scrollController and a critical race condition in the scrollDown method. These findings highlight important areas for improving the stability and performance of the application.
| void scrollDown() async { | ||
| if (_scrollController.hasClients) { | ||
| await Future.delayed(const Duration(milliseconds: 250)); | ||
| _scrollController.animateTo( | ||
| _scrollController.position.maxScrollExtent, | ||
| duration: const Duration(milliseconds: 200), | ||
| curve: Curves.easeOut, | ||
| ); | ||
| } |
There was a problem hiding this comment.
There is a race condition here. The _scrollController.hasClients check is performed before an await. After the Future.delayed completes, the widget might have been disposed, and _scrollController might no longer have clients. Accessing _scrollController.position would then throw an exception. The checks for mounted and hasClients (or positions.isNotEmpty) should be performed after any await calls to ensure the state is still valid before using the controller.
| void dispose() { | ||
| _scrollController.dispose(); | ||
| _questionAnimationController.dispose(); | ||
| super.dispose(); | ||
| } |
|
so _scrollController.hasClients does not work? |
hasClients only checks that the controller is attached at that moment. Since scrollDown waits before running, the list can detach in between so accessing position will crash |
https://github.com/BasedHardware/omi/blob/ef7ad36e5d2c0e1776efe712bcd1cacdada03d86/app/lib/pages/speech_profile/page.dart#L85 ScrollController had no attached position because the ListView was not built yet, that’s whyu position became invalid closes BasedHardware#4023
omi/app/lib/pages/speech_profile/page.dart
Line 85 in ef7ad36
ScrollController had no attached position because the ListView was not built yet, that’s whyu position became invalid
closes #4023