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

AnimationController.dispose() called more than once #58

Closed
JagandeepBrar opened this issue Mar 8, 2020 · 7 comments
Closed

AnimationController.dispose() called more than once #58

JagandeepBrar opened this issue Mar 8, 2020 · 7 comments

Comments

@JagandeepBrar
Copy link

Describe the bug
When using TyperAnimatedTextKit in a widget that will eventually get removed, an error is shown because the animation controller is attempted to be destroyed multiple times.

To Reproduce
In my use case, I have a FutureBuilder that calls a "Loading" widget (Which contains a TyperAnimatedTextKit), and once the data is loaded FutureBuilder removes the loading widget and replaces it with the content widgets.

Expected behavior
It still works, and it doesn't cause a crash but it prints out to the command line each time (as well as logs internally in my logger).

Screenshots

AnimationController#54de2(⏭ 1.000; paused; DISPOSED)] [Exception: AnimationController.dispose() called more than once.
A given AnimationController cannot be disposed more than once.
The following AnimationController object was disposed multiple times:
  AnimationController#54de2(⏭ 1.000; paused; DISPOSED)] [LogLevel.FATAL] [March 08, 2020 - 06:31:29 PM] [#0      AnimationController.dispose.<anonymous closure> 
package:flutter/…/animation/animation_controller.dart:751
#1      AnimationController.dispose 
package:flutter/…/animation/animation_controller.dart:762
#2      _TyperState._nextAnimation 
package:animated_text_kit/src/typer.dart:190
#3      _rootRun  (dart:async/zone.dart:1122:38)
#4      _CustomZone.run  (dart:async/zone.dart:1023:19)
#5      _CustomZone.runGuarded  (dart:async/zone.dart:925:7)
#6      _CustomZone.bindCallbackGuarded.<anonymous closure>  (dart:async/zone.dart:965:23)
#7      _rootRun  (dart:async/zone.dart:1126:13)
#8      _CustomZone.run  (dart:async/zone.dart:1023:19)
#9      _CustomZone.bindCallback.<anonymous closure>  (dart:async/zone.dart:949:23)
#10     Timer._createTimer.<anonymous closure>  (dart:async-patch/timer_patch.dart:23:15)
#11     _Timer._runTimers  (dart:isolate-patch/timer_impl.dart:384:19)
#12     _Timer._handleMessage  (dart:isolate-patch/timer_impl.dart:418:5)
#13     _RawReceivePortImpl._handleMessage  (dart:isolate-patch/isolate_patch.dart:174:12)
]

Flutter:

  • v1.12.13+hotfix.8
  • Stable

Dart:

  • 2.7.0
@awhitford
Copy link
Collaborator

I am seeing a similar issue with a single FadeAnimatedTextKit:

[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: AnimationController.dispose() called more than once.
A given AnimationController cannot be disposed more than once.
The following AnimationController object was disposed multiple times:
  AnimationController#88138(⏭ 1.000; paused; DISPOSED)
#0      AnimationController.dispose.<anonymous closure> (package:flutter/src/animation/animation_controller.dart:751:9)
#1      AnimationController.dispose (package:flutter/src/animation/animation_controller.dart:762:6)
#2      _RotatingTextState._nextAnimation (package:animated_text_kit/src/fade.dart:207:42)
#3      _rootRun (dart:async/zone.dart:1122:38)
#4      _CustomZone.run (dart:async/zone.dart:1023:19)
#5      _CustomZone.runGuarded (dart:async/zone.dart:925:7)
#6      _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:965:23)
#7      _rootRun (dart:async/zone.dart:1126:13)
#8      _CustomZone.run (dart:async/zone.dart:1023:19)
#9      _CustomZone.bindCallback.<anonymous closur<…>

@awhitford
Copy link
Collaborator

The problem appears during a screen transition, so the widget's dispose is conflicting with this code in nextAnimation:

    if (_controller != null) _controller.dispose();

    setState(() {});

    _controller = new AnimationController(
      duration: _duration,
      vsync: this,
    );

I recommend refactoring such that the lifecycle of the AnimationController is closely linked to the widget lifecycle. In other words, I would avoid replacing it during nextAnimation -- instead, just reset it or something.

Of course, the simplest solution may be simply to null it after you dispose it. So, replace:

    if (_controller != null) _controller.dispose();

with

    _controller?.dispose();
    _controller = null;

Then, you will need to add a guard to the widget's dispose method too:

   if (null != _controller) {
    _controller
      ..stop()
      ..dispose();
    }

@aadarshadhakalg
Copy link

Beside of the TyperAnimatedTextKit widget, have you used any other animation ? I mean have you created your custom animation controller in same file?

@yiminghan
Copy link
Contributor

I'm getting into the same issue. I agree with @awhitford we should just set the controller to null after dispose.

aagarwal1012 added a commit that referenced this issue May 18, 2020
* Rotating text : add animation objects and controller

* Rotating text : add text widgets

* Rotating text : nested text widgets with animation builder

* Rotating text : working

* Typer : removed addlisteners for animations

* Rotating text : removed animation listeners and code cleanup

* Typewriter : partially working code

* Typewriter : working

* Typewriter : added default parameter for duration and made text @required for all

* refractor names

* Fade : working

* Colorizer : gradient text made

* Typewriter : dart analuysis error removed

* Colorizer : working

* Colorizer : updated ui

* Colorizer : refrator name

* Colorize : added tuning parameter

* Colorize : made text string to list and added fade animation

* Colorize : added default value of duration

* fixed some ui

* Typewriter : added default value of duration

* Typewriter : added else value of duration

* Colorize : added default value of duration

* Fade : added default value of duration

* Rotate : added default value of duration and added a new parameter transition height and added its default value

* Typer : added default value of duration

* Rotate : change slide curve to linear

* fade : change fade curve to linear

* Scale : working

* Scale : added scaling parameter

* Made basic example app ui

* Added fonts

* made theme for typer and typewriter

* made theme for rest animated texts

* showcase completed

* added cover widget

* fixed play button alignment

* Typer : updated default value of duration

* added labels for animations in ui

* added smoke test {not working}

* fixed testing errors

* Updated LICENSE

* added example app testing in travis.yaml

* added preview gifs

* fixed formatting issues

* initial release 1.0.1

* Updated README.md

* updated flutter version compatibility

* fixed flutter compatibility issues

* Added CODE_OF_CONDUCT.md

* Update issue templates

* Added contributing.md and updated readme

* Added pull request template

* Updated readme and contributions.md

* Updated version to 1.0.2

* added table of contents to readme

* Updated pull request section in contributing.md

* Update travis.yaml and contributing.md

* Remove travis build errors

* 🎨 fix formating in test file

* 🎉 update version to 1.0.3

* ⬆️ added onTap event for all text animations

* ⬆️ updated example

* 🐛 changed InkWell widget to GestureDetector for the onTap event

* 🔥 fixed formatting issues

* 🐛 fixed dart analysis issues

* 🎉 updated to version 1.1.0

* 💚 added some animations for the roadmap

* 🐛 fixed formatting issues

* add .idea to .gitignore

* Expand .gitignore, Add flag for running animation once, update gradle.

* 🐛 fixed fading with isRepeatingAnimation is set false

* 📝 added isRepeatingAnimation to Readme

* 🎉 updated version to 1.2.0

* Added alignment property to Stack and textAlign property to Text

* Added GenericAnimatedTextKit to simplify some initialization
Added some common assertions

* Revert "Added GenericAnimatedTextKit to simplify some initialization"

This reverts commit 1dc30cc.

* Updated README.md.

Added the usage of "textAlign" and "alignment" properties

* 🐛 fixed opacity value in typer

* 🎉 updated to 1.3.0

* Updated Readme

* docs: added documentation for the various parameters of all the animated text widgets

* docs: updated example app readme

* conf: updated travis script

* conf: updated package to version 1.3.1

* conf: create funding.yml

* docs: updated docs for duration parameter

* docs: updated contributing.md

* bfix: fixed travis

* conf: added codecov coverage

* docs: add salihgueler as a contributor (#36)

* docs: update README.md

* docs: create .all-contributorsrc

* docs: updated readme

* docs: add anderscheow as a contributor (#37)

* docs: update README.md

* docs: update .all-contributorsrc

* docs: add r1walz as a contributor (#38)

* docs: update README.md

* docs: update .all-contributorsrc

* Enhanced different classes of AnimatedTextKit

* Fixed travis issue

* Typer Class Enhancments (#40)

* Typer Class Enhancments

Refer to issue #34
The Typer Class has been greatly improved in term of control. 

### Let's start with breaking changes : 
####The duration parameter has become two new ones : speed and pause
  * speed is the elapsed time between the animation of each characters of a text (Default is 40 ms)
  * pause is the pause duration between texts (Default is 500 ms)

### New features : 
####Three new callbacks come alongside the onTap :  
  * onNext(int index, bool isLast) - This callback will be called before the next text animation, after the previous one's pause. 
  * onNextBeforePause(int index, bool isLast) - This callback will be called before the next text animation, before the previous one's pause. 
  * onFinished - This callback is called at the end, if the parameter isRepeatingAnimation is set to false
####Two new arguments : 
  * displayFullTextOnTap - If true, tapping the screen will stop current animated text, and display it fully for min(remaining, pause) time. (Default is false)
  * stopPauseOnTap - If true, tapping during a pause will stop it and start the next text animation (Default is false)
####The text list parameter now accept either strings, or map where you can give a text custom speed and pause.

If you like thoses changes, I'll make another commit with updated readme regarding this PR with code examples.

* Fix indentation issues for Travis

* Fix indentation issues for Travis

* Fix formating issue in travis

* chor: deleted flutter_export_environment.sh file (unnecessary)

* Addeed TextLiquidFill animation to AnimatedTextKit

* chor: fixed formatting issues

* bfix: fixed Travis fail

* conf: updated to version 2.0.0

* chor: updated readme

* docs: add AdamSGit as a contributor (#49)

* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

* docs: add hemilpanchiwala as a contributor (#50)

* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

* docs: added text liquid fill medium blog link in Readme

* feat: updated to v2.0.1 (#67)

* #44 fix

* added gitignore

* gitignore

* Issue 58

* Changed back to default example

Co-authored-by: aagarwal1012 <[email protected]>
Co-authored-by: r1walz <[email protected]>
Co-authored-by: Muhammed Salih Guler <[email protected]>
Co-authored-by: Anders Cheow <[email protected]>
Co-authored-by: Anders Cheow <[email protected]>
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Hemil Panchiwala <[email protected]>
Co-authored-by: AdamSGit <[email protected]>
@aagarwal1012
Copy link
Owner

v2.1.0 of Animated text kit solves this issue, closing this issue for now. Feel free to reopen this issue if any issue arises.

@awhitford
Copy link
Collaborator

Code like this:

_controller?.stop();
_controller.dispose();

is a problem and it isn't any better than:

_controller
  ..stop()
  ..dispose();

If _controller is null, then the ?. will protect stop(), but then you will get a Null Pointer Exception calling dispose().

Some are fine (rotate, scale), but some are faulty (colorize, fade).

Also, this code:

if (_controller != null) {	    
  _controller
    ..stop()
    ..dispose();
}

is logically the same:

_controller?.stop();
_controller?.dispose();

The latter is more concise, but arguably less efficient (unless the optimizer can optimize the double ?.).

@niumj
Copy link

niumj commented Oct 14, 2022

May be you wrote the source [_controller.dispose();] in the method build.
But Flutter would call build multiple times.So you try to write the code [_controller.dispose();] in the method dispose etc.

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

No branches or pull requests

6 participants