'Flutter VideoPlayerController "setState() or markNeedsBuild() called during build."
I'm playing video and there is no problem but when navigating to another page, console says this.
I tried everything that I came up with like check if mounted
but none of them worked.
What am I missing? Does anyone know how to fix?
flutter: The following assertion was thrown while dispatching notifications for VideoPlayerController:
flutter: setState() or markNeedsBuild() called during build.
flutter: This VideoProgressIndicator widget cannot be marked as needing to build because the framework is
flutter: already in the process of building widgets. A widget can be marked as needing to be built during the
flutter: build phase only if one of its ancestors is currently building. This exception is allowed because
flutter: the framework builds parent widgets before children, which means a dirty descendant will always be
flutter: built. Otherwise, the framework might not visit this widget during this build phase.
flutter: The widget on which setState() or markNeedsBuild() was called was:
flutter: VideoProgressIndicator(state: _VideoProgressIndicatorState#09ac7)
Code:
class _VideoScreenState extends State<VideoScreen> {
VideoPlayerController _controller;
FadeAnimation imageFadeAnim =
new FadeAnimation(child: const Icon(Icons.play_arrow, size: 100.0));
VoidCallback listener;
bool _isPlaying = false;
List<String> videos = [
'http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_20mb.mp4',
];
_VideoScreenState() {
listener = () {
if (mounted) setState(() {});
};
}
Future _videoOnTap() async {
if (!_controller.value.initialized) {
return;
}
if (_controller.value.isPlaying) {
imageFadeAnim = new FadeAnimation(
child: Icon(Icons.pause,
color: Colors.white.withOpacity(0.3), size: 75.0));
await _controller.pause();
} else {
imageFadeAnim = new FadeAnimation(
child: Icon(Icons.play_arrow,
color: Colors.white.withOpacity(0.3), size: 75.0));
await _controller.play();
}
}
Future _startVideoPlayer(int index) async {
if (_controller != null) {
await _controller.dispose();
}
_controller = VideoPlayerController.network(videos[index])
..addListener(() {
final bool isPlaying = _controller.value.isPlaying;
if (isPlaying != _isPlaying) {
if (mounted)
setState(() {
_isPlaying = isPlaying;
});
}
})
..initialize().then((_) async {
await _controller.play();
if (mounted) setState(() {});
});
}
@override
void initState() {
SystemChrome.setEnabledSystemUIOverlays([]);
_startVideoPlayer(0);
super.initState();
}
@override
void deactivate() {
_controller?.setVolume(0.0);
_controller?.removeListener(listener);
super.deactivate();
}
@override
void dispose() {
_controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final List<Widget> children = <Widget>[
new GestureDetector(
child: new Center(
child: _controller.value.initialized
? new AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: new VideoPlayer(_controller))
: new Container(),
),
onTap: _videoOnTap,
),
new Align(
alignment: Alignment.topCenter,
child: new VideoProgressIndicator(
_controller,
allowScrubbing: false,
colors: VideoProgressColors(
backgroundColor: Colors.black.withOpacity(0.5),
playedColor: Colors.white),
),
),
new Center(child: imageFadeAnim),
];
return new Scaffold(
backgroundColor: Colors.black,
body: new SafeArea(
top: true,
left: false,
right: false,
bottom: false,
child: new Stack(
fit: StackFit.passthrough,
children: children,
),
),
);
}
}
class FadeAnimation extends StatefulWidget {
final Widget child;
final Duration duration;
FadeAnimation({this.child, this.duration: const Duration(milliseconds: 300)});
@override
_FadeAnimationState createState() => new _FadeAnimationState();
}
class _FadeAnimationState extends State<FadeAnimation>
with SingleTickerProviderStateMixin {
AnimationController animationController;
@override
void initState() {
super.initState();
animationController =
new AnimationController(duration: widget.duration, vsync: this);
animationController.addListener(() {
if (mounted) {
setState(() {});
}
});
animationController.forward(from: 0.0);
}
@override
void deactivate() {
animationController.stop();
super.deactivate();
}
@override
void didUpdateWidget(FadeAnimation oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.child != widget.child) {
animationController.forward(from: 0.0);
}
}
@override
void dispose() {
animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return animationController.isAnimating
? new Container(
width: 75.0,
height: 75.0,
decoration: new BoxDecoration(
color: Colors.black.withOpacity(0.01),
shape: BoxShape.circle,
),
child: widget.child,
)
: new Container();
}
}
Solution 1:[1]
Initialize your animationController in initState and add listener to didchangeDependencies
@override
void initState() {
super.initState();
animationController =
new AnimationController(duration: widget.duration, vsync: this);
}
@override
void didChangeDependencies(
{
super.didChangeDependencies();
animationController.addListener(() {
if (mounted) {
setState(() {});
}
});
animationController.forward(from: 0.0);
})
Solution 2:[2]
Seems to me the OP needs to include the code to VideoProgressIndicator to debug their particular issue, but generally when facing this error you'll want to use WidgetsBinding.instance.addPostFrameCallback to prevent Navigator methods or setState from being invoked during the build phase, e.g.
WidgetsBinding.instance.addPostFrameCallback(
(_) => setState(() => _isPlaying = !_isPlaying),
);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Nbn |
Solution 2 | Chris Wickens |