Flutter:在构建期间调用setState()或markNeedsBuild() [英] Flutter: setState() or markNeedsBuild() called during build

查看:53
本文介绍了Flutter:在构建期间调用setState()或markNeedsBuild()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个显示视频的页面.但是,当我完成视频并跳回到上一页时,出现此错误消息.我的应用程序运行良好,没有间断,但是下面的错误困扰着我.

I have a page that shows video. But when I complete the video and pop back to the previous page I get this bellow error. My app works all fine and good with no breaks, but this below error bothers me.

setState()或markNeedsBuild()是我无法修复的错误

我需要帮助来纠正此错误.

I need help to fix this error.

这是我的错误:

══╡ EXCEPTION CAUGHT BY FOUNDATION LIBRARY ╞════════════════════════════════════════════════════════
The following assertion was thrown while dispatching notifications for VideoPlayerController:
setState() or markNeedsBuild() called during build.
This VideoPlayerScreen widget cannot be marked as needing to build because the framework is already
in the process of building widgets.  A widget can be marked as needing to be built during the build
phase only if one of its ancestors is currently building. This exception is allowed because the
framework builds parent widgets before children, which means a dirty descendant will always be
built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was:
  VideoPlayerScreen
The widget which was currently being built when the offending call was made was:
  Overlay-[LabeledGlobalKey<OverlayState>#e44a5]

When the exception was thrown, this was the stack:
#0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:4211:11)
#1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4226:6)
#2      State.setState (package:flutter/src/widgets/framework.dart:1260:14)
#3      _VideoPlayerScreenState._listener (package:flow/widget/page/video_player.dart:52:7)
#4      ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:209:21)
#5      ValueNotifier.value= (package:flutter/src/foundation/change_notifier.dart:276:5)
#6      VideoPlayerController.pause (package:video_player/video_player.dart:360:5)
#7      _VideoPlayerScreenState.deactivate (package:/widget/page/video_player.dart:175:34)
(elided 3 frames from dart:async)

The VideoPlayerController sending notification was:
  VideoPlayerController#619c5(VideoPlayerValue(duration: 0:10:55.430000, size: Size(1920.0, 1080.0),
  position: 0:10:55.430000, caption: Instance of 'Caption', buffered: [DurationRange(start:
  0:00:00.000000, end: 0:10:55.430000)], isPlaying: false, isLooping: false, isBuffering:
  falsevolume: 1.0, errorDescription: null))
════════════════════════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by foundation library ════════════════════════════════════════════════════
The following assertion was thrown while dispatching notifications for VideoPlayerController:
setState() or markNeedsBuild() called during build.

This VideoPlayerScreen widget cannot be marked as needing to build because the framework is already in the process of building widgets.  A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: VideoPlayerScreen
  dependencies: [_InheritedTheme, _LocalizationsScope-[GlobalKey#fe7c2], MediaQuery]
  state: _VideoPlayerScreenState#4559e
The widget which was currently being built when the offending call was made was: Overlay-[LabeledGlobalKey<OverlayState>#e44a5]
  state: OverlayState#cf68b(entries: [OverlayEntry#517dd(opaque: true; maintainState: false), OverlayEntry#87d9a(opaque: false; maintainState: true)])
When the exception was thrown, this was the stack: 
#0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:4211:11)
#1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4226:6)
#2      State.setState (package:flutter/src/widgets/framework.dart:1260:14)
#3      _VideoPlayerScreenState._listener (package:flow/widget/page/video_player.dart:52:7)
#4      ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:209:21)
...
The VideoPlayerController sending notification was: VideoPlayerController#619c5(VideoPlayerValue(duration: 0:10:55.430000, size: Size(1920.0, 1080.0), position: 0:10:55.430000, caption: Instance of 'Caption', buffered: [DurationRange(start: 0:00:00.000000, end: 0:10:55.430000)], isPlaying: false, isLooping: false, isBuffering: falsevolume: 1.0, errorDescription: null))
════════════════════════════════════════════════════════════════════════════════════════════════════
I/ExoPlayerImpl(24022): Release 569e95d [ExoPlayerLib/2.9.6] [tissot_sprout, Mi A1, Xiaomi, 28] [goog.exo.core]
E/BufferQueueProducer(24022): [SurfaceTexture-0-24022-9] cancelBuffer: BufferQueue has been abandoned
D/SurfaceUtils(24022): disconnecting from surface 0x70a0b7e010, reason disconnectFromSurface

这是我的代码:

class VideoPlayerScreen extends StatefulWidget {
  final VideoPlayerController videoPlayerController;

  const VideoPlayerScreen({
    Key key,
    @required this.videoPlayerController,
  }) : super(key: key);

  @override
  _VideoPlayerScreenState createState() => _VideoPlayerScreenState();
}

class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
  bool _buttonEnabled = false;
  VideoPlayerController _videoPlayerController;
  int playBackTime = 0;
  //VoidCallback _listener;
  void _listener() {
    if (_videoPlayerController.value.position ==
        _videoPlayerController.value.duration) {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        if (mounted) {
          setState(() {
            _buttonEnabled = true;
          });
        }
      });
    }
    if (mounted) {
      setState(() {
        playBackTime = _videoPlayerController.value.position.inSeconds;
      });
    }
  }

  @override
  void initState() {
    _videoPlayerController = widget.videoPlayerController;
    _videoPlayerController
      ..addListener(_listener)
      ..initialize().then((_) {
        _videoPlayerController.play();
        setState(() {});
      });
    SystemChrome.setPreferredOrientations([
      DeviceOrientation.landscapeLeft,
      //DeviceOrientation.landscapeRight,
    ]);
    AutoOrientation.landscapeAutoMode();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    //final length = MediaQuery.of(context).size;
    return SingleChildScrollView(
      child: Stack(
        children: <Widget>[
          _videoPlayerController.value.initialized
              ? _playerWidget()
              : Center(
                  child: CircularProgressIndicator(),
                ),
          Visibility(
            visible: _buttonEnabled,
            child: Container(),
          
          ),
        ],
      ),
    );
  }


  _playAndPauseButton() {
    return InkWell(
      child: Icon(
        _videoPlayerController.value.isPlaying ? Icons.pause : Icons.play_arrow,
        color: Theme.of(context).buttonColor,
        size: 25,
      ),
      onTap: () {
        _videoPlayerController.value.isPlaying
            ? _videoPlayerController.pause()
            : _videoPlayerController.play();
      },
    );
  }

  _slider() {
    final length = MediaQuery.of(context).size;
    return Container(
      width: length.width * 0.85,
      child: SliderTheme(
        data: SliderTheme.of(context).copyWith(
          activeTrackColor: Colors.black,
          inactiveTrackColor: Colors.grey,
          trackHeight: 1.0,
          thumbColor: Colors.yellow,
          thumbShape: RoundSliderThumbShape(enabledThumbRadius: 6.0),
        ),
        child: Slider(
            max: _videoPlayerController.value.duration.inSeconds.toDouble(),
            min: 0.0,
            value: playBackTime.toDouble(),
            onChanged: (v) {
              _videoPlayerController.seekTo(Duration(seconds: v.toInt()));
            }),
      ),
    );
  }

  _playerWidget() {
    final length = MediaQuery.of(context).size;
    return GestureDetector(
      onTap: () {
        final snackBar = SnackBar(
          content: Container(
            height: length.height * 0.02,
            width: length.width,
            child: Row(
              children: [
                _playAndPauseButton(),
                _slider(),
              ],
            ),
          ),
        );
        Scaffold.of(context).showSnackBar(snackBar);
      },
      child: AspectRatio(
        aspectRatio: _videoPlayerController.value.aspectRatio,
        child: VideoPlayer(_videoPlayerController),
      ),
    );
  }

  @override
  void deactivate() {
    widget.videoPlayerController.pause();
    super.deactivate();
  }

  @override
  void dispose() {
    widget.videoPlayerController.dispose();
    SystemChrome.setPreferredOrientations([
      DeviceOrientation.landscapeRight,
      DeviceOrientation.landscapeLeft,
      DeviceOrientation.portraitUp,
      DeviceOrientation.portraitDown,
    ]);
    AutoOrientation.landscapeAutoMode();
    AutoOrientation.portraitUpMode();
    super.dispose();
  }
}

推荐答案

尝试处置 videoController :

@override
  void dispose() {
    widget.videoPlayerController?.dispose();
    _videoPlayerController.removeListener(_listener);
    _videoPlayerController.dispose();
    super.dispose();
  }

最后将 void _listener()更改为:

void _listener() {
    if (_videoPlayerController.value.position ==
        _videoPlayerController.value.duration) {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        if (mounted) {
          setState(() {
            _buttonEnabled = true;
          });
        }
      });
    }
    WidgetsBinding.instance.addPostFrameCallback((__) {
      if (mounted) {
        setState(() {
          playBackTime = _videoPlayerController.value.position.inSeconds;
        });
      }
    });
  }

这篇关于Flutter:在构建期间调用setState()或markNeedsBuild()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆