DavideBelsole / great_list_view

pub.dev library for flutter
MIT License
39 stars 21 forks source link

Issue: setState() or markNeedsBuild() called when widget tree was locked. #28

Open AntonShynkaretskyi opened 1 year ago

AntonShynkaretskyi commented 1 year ago

If an item in AutomaticAnimatedListView has an SVG image rendered by the flutter_svg library, I'm getting exceptions.

After a bit of googling it seems to be a more common issue than just with the SVG library. E.g. https://stackoverflow.com/questions/60852896/widget-cannot-be-marked-as-needing-to-build-because-the-framework-is-already-in

The library I'm using is flutter_svg: ^2.0.1: https://pub.dev/packages/flutter_svg

Stack trace:

======== Exception caught by SVG ===================================================================
The following assertion was thrown by a synchronously-called image listener:
setState() or markNeedsBuild() called when widget tree was locked.

This SvgPicture widget cannot be marked as needing to build because the framework is locked.
The widget on which setState() or markNeedsBuild() was called was: SvgPicture
  dirty
  dependencies: [DefaultTextStyle, Directionality, _LocalizationsScope-[GlobalKey#1c2fb]]
  state: _SvgPictureState#b3489(lifecycle state: initialized, stream: PictureStream#f79df(OneFramePictureStreamCompleter#c6c6f, Instance of 'PictureInfo', 7 listeners, cached))
When the exception was thrown, this was the stack: 
#0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:4636:9)
#1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4646:6)
#2      State.setState (package:flutter/src/widgets/framework.dart:1153:15)
#3      _SvgPictureState._handleImageChanged (package:flutter_svg/svg.dart:814:5)
#4      PictureStreamCompleter.addListener (package:flutter_svg/src/picture_stream.dart:297:17)
#5      PictureStream.addListener (package:flutter_svg/src/picture_stream.dart:204:26)
#6      _SvgPictureState._listenToStream (package:flutter_svg/svg.dart:843:21)
#7      _SvgPictureState.didChangeDependencies (package:flutter_svg/svg.dart:752:5)
#8      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5119:11)
#9      ComponentElement.mount (package:flutter/src/widgets/framework.dart:4944:5)
...     Normal element mounting (7 frames)
#16     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3953:16)
#17     MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6512:36)
#18     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6524:32)
#19     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3953:16)
#20     MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6512:36)
#21     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6524:32)
#22     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3953:16)
#23     MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6512:36)
#24     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6524:32)
#25     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3953:16)
#26     MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6512:36)
#27     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6524:32)
...     Normal element mounting (7 frames)
#34     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3953:16)
#35     MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6512:36)
#36     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6524:32)
...     Normal element mounting (254 frames)
#290    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3953:16)
#291    Element.updateChild (package:flutter/src/widgets/framework.dart:3682:18)
#292    AnimatedSliverMultiBoxAdaptorElement.updateChild (package:great_list_view/src/child_manager.dart:552:28)
#293    AnimatedSliverMultiBoxAdaptorElement.disposableElement.<anonymous closure> (package:great_list_view/src/child_manager.dart:651:36)
#294    BuildOwner.lockState (package:flutter/src/widgets/framework.dart:2601:15)
#295    AnimatedSliverMultiBoxAdaptorElement.disposableElement (package:great_list_view/src/child_manager.dart:647:12)
#296    AnimatedRenderSliverList.measureItem (package:great_list_view/src/sliver_list.dart:1011:18)
#297    AnimatedRenderSliverList.measureItems.<anonymous closure> (package:great_list_view/src/sliver_list.dart:998:17)
#302    _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:192:26)
(elided 4 frames from class _Timer, dart:async, and dart:async-patch)
====================================================================================================

PS: Thanks for the library, might become an awesome alternative to Android's ListView with auto diff animations :)

Vovcharaa commented 1 year ago

I have the same issue with OctoImage https://github.com/Baseflow/octo_image/issues/28

AntonShynkaretskyi commented 1 year ago

I have the same issue with OctoImage Baseflow/octo_image#28

Meanwhile, if you want a nice alternative, I settled on https://pub.dev/packages/implicitly_animated_reorderable_list_2

Vovcharaa commented 1 year ago

@AntonShynkaretskyi Thanks, I will look into it.

DavideBelsole commented 1 year ago

You are free to switch to other libraries if you wish, however I point out that this library was created precisely because I felt the other libraries were inadequate and full of bugs, given the complexity behind animating a list. I feel that my library is well programmed and much more robust enough to handle even multiple change requests while animating on virtually infinite lists. Try doing the same with other libraries and you will see the limitations they have. However, this library is still in alpha version, and your input is invaluable in finalizing it.

Getting back to the error, the problem lies in the item measurement when a remove/insert animation occurs. In your builder try providing an equivalent widget that has the same height when AnimatedWidgetBuilderData.measuring = true (as described in the documentation); it will definitely solve the issue. However I will investigate it to find a solution to your problem.

Vovcharaa commented 1 year ago

@DavideBelsole Thanks for the provided solution. Indeed, it solved the issue.

AntonShynkaretskyi commented 1 year ago

I feel that my library is well programmed and much more robust enough to handle even multiple change requests while animating on virtually infinite lists.

That's my impression as well

Getting back to the error, the problem lies in the item measurement when a remove/insert animation occurs. In your builder try providing an equivalent widget that has the same height when AnimatedWidgetBuilderData.measuring = true (as described in the documentation); it will definitely solve the issue.

It does result in the stack trace being gone. But I don't have the real height of the items, and falling back to 60 (as in the example) or any other value makes the animation to jump weirdly

DavideBelsole commented 1 year ago

If you don't provide the right height, it's normal for it to jump weirdly, For now, roughly solve it this way so you don't get stuck with your development. In the meantime I have already fixed the issue and in these days I will release several fixes including this one.

yairsts commented 11 months ago

Try this for fix the problem:

AutomaticAnimatedListView( list: data, padding: widget.padding ?? const EdgeInsets.all(16.0), comparator: AnimatedListDiffListComparator(sameItem: widget.sameItem, sameContent: widget.sameContent), itemBuilder: (context, item, data) => data.measuring ? const SizedBox.shrink() : widget.itemBuilder(item), listController: controller, addLongPressReorderable: false, reorderModel: AutomaticAnimatedListReorderModel(data), detectMoves: true, );

AntonShynkaretskyi commented 8 months ago

I have already fixed the issue and in these days I will release several fixes including this one

@DavideBelsole, could you please release what's ready if it's not too much effort? Thanks :)

JasCodes commented 8 months ago

@AntonShynkaretskyi Just check for AnimatedWidgetBuilderData.measuring = true and pass dummy equivalent empty layout widget.