Flutter VideoPlayerController “在构建期间调用了 setState() 或 markNeedsBuild()。”

Posted

技术标签:

【中文标题】Flutter VideoPlayerController “在构建期间调用了 setState() 或 markNeedsBuild()。”【英文标题】:Flutter VideoPlayerController "setState() or markNeedsBuild() called during build." 【发布时间】:2019-02-19 23:53:04 【问题描述】:

我正在播放视频,没有问题,但是当导航到另一个页面时,控制台会这样说。 我尝试了我想出的所有方法,例如检查 mounted 是否有效。 我错过了什么?有人知道怎么解决吗?

flutter:在为 VideoPlayerController 调度通知时抛出以下断言: 颤振:在构建期间调用 setState() 或 markNeedsBuild()。 颤振:这个 VideoProgressIndicator 小部件无法标记为需要构建,因为框架是 颤振:已经在构建小部件的过程中。小部件可以在期间标记为需要构建 颤振:仅当其祖先之一当前正在构建时才构建阶段。这个例外是允许的,因为 Flutter:框架在子组件之前构建父组件,这意味着脏的后代将永远是 扑:建成。否则,框架可能不会在此构建阶段访问此小部件。 颤振:调用 setState() 或 markNeedsBuild() 的小部件是: 颤振:VideoProgressIndicator(状态:_VideoProgressIndicatorState#09ac7)

代码:

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();
      
    

【问题讨论】:

我也有同样的问题。有什么解决办法吗? 解决了什么问题? 这里也一样,有人提出过解决办法吗? 它肯定与 deactivate() 中的 _controller?.setVolume(0.0) 有关。没有机会更详细地研究它。但我猜该代码中的某个地方可能会调用 setState 本身。 【参考方案1】:

在 initState 中初始化你的 animationController 并将监听器添加到 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);
)

【讨论】:

以上是关于Flutter VideoPlayerController “在构建期间调用了 setState() 或 markNeedsBuild()。”的主要内容,如果未能解决你的问题,请参考以下文章

[Flutter] flutter项目一直卡在 Running Gradle task 'assembleDebug'...

flutter 日志输出,Flutter打印日志,flutter log,flutter 真机日志

Flutter开发 Flutter 包和插件 ( Flutter 包和插件简介 | 创建 Flutter 插件 | 创建 Dart 包 )

flutter与原生混编(iOS)

Flutter-布局

如何解决flutter gradle build error?C:\flutter\packages\flutter_tools\gradle\flutter.gradle' line: 991