indexed_list_view icon indicating copy to clipboard operation
indexed_list_view copied to clipboard

ScrollController attached to multiple scroll views

Open AAverin opened this issue 2 years ago • 7 comments

Somehow, changing the controller, list gets rebuild but is not functional, as underlying scroll controller ends up being attached to multiple places.

When the exception was thrown, this was the stack: 
#2      ScrollController.position (package:flutter/src/widgets/scroll_controller.dart:108:12)
#3      ScrollController.offset (package:flutter/src/widgets/scroll_controller.dart:115:24)
#4      my code reading controller.offset
#5      ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:308:24)
#6      ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:308:24)
#7      ScrollPosition.notifyListeners (package:flutter/src/widgets/scroll_position.dart:969:11)
#8      ScrollPosition.setPixels (package:flutter/src/widgets/scroll_position.dart:278:9)
#9      ScrollPositionWithSingleContext.setPixels (package:flutter/src/widgets/scroll_position_with_single_context.dart:82:18)

I will try to dig deeper into the code to find an issue and suggest a fix, but maybe it is a known issue already?

AAverin avatar Sep 06 '22 13:09 AAverin

There is also this exception. Controller indeed got disposed already as I am rebuilding the whole screen with the list, so there is a new controller.

A IndexedScrollController was used after being disposed.

Once you have called dispose() on a IndexedScrollController, it can no longer be used.
The relevant error-causing widget was: 
  Container Container:file:///Volumes/MyData/Projects/Personal/PhotoHound/flutter_photohound/photo_hound/lib/components/common/TimeSlider.dart:260:24
When the exception was thrown, this was the stack: 
#0      ChangeNotifier._debugAssertNotDisposed.<anonymous closure> (package:flutter/src/foundation/change_notifier.dart:114:9)
#1      ChangeNotifier._debugAssertNotDisposed (package:flutter/src/foundation/change_notifier.dart:120:6)
#2      ChangeNotifier.removeListener (package:flutter/src/foundation/change_notifier.dart:233:12)
#3      _IndexedListViewState.didUpdateWidget (package:indexed_list_view/indexed_list_view.dart:170:28)
#4      StatefulElement.update (package:flutter/src/widgets/framework.dart:4943:57)
#5      Element.updateChild (package:flutter/src/widgets/framework.dart:3501:15)
#6      SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6291:14)
#7      Element.updateChild (package:flutter/src/widgets/framework.dart:3501:15)
#8      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4780:16)
#9      Element.rebuild (package:flutter/src/widgets/framework.dart:4477:5)
#10     StatelessElement.update (package:flutter/src/widgets/framework.dart:4834:5)
#11     Element.updateChild (package:flutter/src/widgets/framework.dart:3501:15)
#12     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4780:16)
#13     Element.rebuild (package:flutter/src/widgets/framework.dart:4477:5)
#14     ProxyElement.update (package:flutter/src/widgets/framework.dart:5108:5)
#15     Element.updateChild (package:flutter/src/widgets/framework.dart:3501:15)
#16     RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:5787:32)
#17     MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6445:17)
#18     Element.updateChild (package:flutter/src/widgets/framework.dart:3501:15)
#19     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6291:14)
#20     Element.updateChild (package:flutter/src/widgets/framework.dart:3501:15)
#21     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4780:16)
#22     Element.rebuild (package:flutter/src/widgets/framework.dart:4477:5)
#23     StatelessElement.update (package:flutter/src/widgets/framework.dart:4834:5)
#24     Element.updateChild (package:flutter/src/widgets/framework.dart:3501:15)
#25     RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:5787:32)
#26     MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6445:17)
#27     Element.updateChild (package:flutter/src/widgets/framework.dart:3501:15)
#28     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4780:16)
#29     Element.rebuild (package:flutter/src/widgets/framework.dart:4477:5)
#30     StatelessElement.update (package:flutter/src/widgets/framework.dart:4834:5)
#31     HookElement.update (package:flutter_hooks/src/framework.dart:378:11)
#32     Element.updateChild (package:flutter/src/widgets/framework.dart:3501:15)
#33     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4780:16)
#34     Element.rebuild (package:flutter/src/widgets/framework.dart:4477:5)
#35     ProxyElement.update (package:flutter/src/widgets/framework.dart:5108:5)
#36     Element.updateChild (package:flutter/src/widgets/framework.dart:3501:15)
#37     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4780:16)
#38     Element.rebuild (package:flutter/src/widgets/framework.dart:4477:5)
#39     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2659:19)
#40     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:882:21)
#41     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:363:5)
#42     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1144:15)
#43     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1081:9)
#44     SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:862:7)

AAverin avatar Sep 06 '22 14:09 AAverin

Funny thing I noticed is that underlying Scrollable.didChangeWidget() doesn't get invoked when controller is changed

AAverin avatar Sep 06 '22 14:09 AAverin

One more extra exception I get afterwards:

======== Exception caught by widgets library =======================================================
The following assertion was thrown building HookBuilder(useValueListenable: false, useValueListenable: CameraPosition(bearing: -0.0, target: LatLng(49.603974947644545, 12.627328350029586), tilt: 0.0, zoom: 4.962529878031322), useValueListenable: null, useValueListenable: null):
'package:flutter/src/widgets/framework.dart': Failed assertion: line 5219 pos 14: '_dependents.isEmpty': is not true.


Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
  https://github.com/flutter/flutter/issues/new?template=2_bug.md

The relevant error-causing widget was: 
  HookBuilder HookBuilder:file:///Volumes/MyData/Projects/Personal/.../AnyMapPage.dart:496:19
When the exception was thrown, this was the stack: 
#2      InheritedElement.debugDeactivated.<anonymous closure> (package:flutter/src/widgets/framework.dart:5219:14)
#3      InheritedElement.debugDeactivated (package:flutter/src/widgets/framework.dart:5221:6)
#4      _InactiveElements._deactivateRecursively.<anonymous closure> (package:flutter/src/widgets/framework.dart:1948:15)
#5      _InactiveElements._deactivateRecursively (package:flutter/src/widgets/framework.dart:1950:6)
#6      MultiChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:6386:16)
#7      _InactiveElements._deactivateRecursively (package:flutter/src/widgets/framework.dart:1946:13)
#8      SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:6271:14)
#9      _InactiveElements._deactivateRecursively (package:flutter/src/widgets/framework.dart:1946:13)

AAverin avatar Sep 07 '22 06:09 AAverin

The cause lies in attach for ScrollController being called twice. Both calls come from didChangeDependencies, and the second call happens on the first scroll event for some reason. Happens only on rebuilds of the list when underlying controller changes.

AAverin avatar Sep 07 '22 07:09 AAverin

Here is a comparison of a correctly attached position after rebuild and a new position, that gets attached on first scroll event of the rebuild list. image

AAverin avatar Sep 07 '22 07:09 AAverin

So the trick seems to be not to change controller for the list and reuse the one that is already there

AAverin avatar Sep 07 '22 07:09 AAverin

Having to reuse controller between multiple instances and rebuilds leads to more troubles as listener updates end up being called for to-be-soon-destroyed-instance, potentially corrupting state

AAverin avatar Sep 08 '22 16:09 AAverin

Hi @AAverin, thanks for filling this issue, and sorry for the delay in responding. Could you please provide me with a single standalone file, with main method and all, that demonstrates and reproduces the above issue, with minimal and simple code?

Thank you.

marcglasberg avatar Nov 25 '22 15:11 marcglasberg

I am closing this. I'll reopen in case you respond. Thanks.

marcglasberg avatar Jan 30 '23 18:01 marcglasberg