【问题标题】:Flutter video_player disposeFlutter video_player 配置
【发布时间】:2019-11-20 13:45:07
【问题描述】:

我使用providervideo_player 来管理状态。

VideoProvider 有:

videoPlayerController = VideoPlayerController.network(...);

当用户切换到新视频(同一屏幕)时,我经常更改它。如果我直接将新的VideoPlayerController.network(...) 分配到videoPlayerController 中,旧视频仍然会播放并且您可以听到声音。解决方法是videoPlayerController.pause(),然后分配一个新的VideoPlayerCOntroller.network

上一个视频是否被 GC 处理?这有任何性能问题吗?我想在切换到新视频之前摆脱以前的视频和使用的资源。我不能在切换之前videoPlayerController.dispose(),因为它会导致错误。

【问题讨论】:

  • 究竟是哪个错误导致的?
  • @IgorKharakhordin videoPlayerController was used after being disposed

标签: flutter dart


【解决方案1】:

当您调用dispose 时,VideoPlayer 小部件仍在使用您的控制器。首先,您需要确保不再使用它(将状态中的控制器设置为 null)并且在您调用 dispose 之后。

我不确定您通过 Provider 进行的状态管理,但我将举一个示例,如何使用常规状态进行此操作。

  VideoPlayerController _controller;

  void _initController(String link) {
    _controller = VideoPlayerController.network(link)
      ..initialize().then((_) {
        setState(() {});
      });
  }

  Future<void> _onControllerChange(String link) async {
    if (_controller == null) {
      // If there was no controller, just create a new one
      _initController(link);
    } else {
      // If there was a controller, we need to dispose of the old one first
      final oldController = _controller;

      // Registering a callback for the end of next frame
      // to dispose of an old controller
      // (which won't be used anymore after calling setState)
      WidgetsBinding.instance.addPostFrameCallback((_) async {
        await oldController.dispose();

        // Initing new controller
        _initController(link);
      });

      // Making sure that controller is not used by setting it to null
      setState(() {
        _controller = null;
      });
    }
  }

【讨论】:

  • 有趣。我以为final oldController = _controller 只是创建了一个新变量,即:按值传递,这使得oldController.dispose() 只影响oldController 而不是_controller 实例。
  • 非常感谢 igor 先生,您的代码完美运行
  • 你真是太棒了,我无法用言语来表达我对你的最美好的祝愿。我正在搜索根据用户请求一一播放多个视频 4 天,今天你让我很开心。我知道设置状态“controller = null;”是我的愚蠢错误在最后的“WidgetsBinding.instance.addPostFrameCallback(() async {”函数中,它应该在这个函数之外。再次感谢亲爱的,保持它并帮助像我一样的其他人。快乐编码:)
  • 你能告诉我把 oldController 做成 final 有什么好处吗?
  • 您好,您在代码中的哪个位置调用 _onControllerChange() ?
【解决方案2】:

我知道它已经晚了,但这将帮助其他有同样问题的人。

我有同样的问题,当用户从列表中选择新视频时,我想更改视频,经过大量研究,我终于自己创建了一个解决方案。

按照以下步骤,您可以在同一屏幕的视频播放器中播放视频

  1. 创建一个包含VideoPlayerStatefulWidget 类,并在init 方法中初始化videoPlayerController。 假设您创建了一个名为 MyVideoPlayer 的 StatefulWidget 类,然后在构造函数中接受两个变量,即 i> 字符串视频链接 ii> UniqueKey()

注意 - 你必须将 UniqueKey() 传递给这个类的父类,例如,

class MyVideoPlayer extends StatefulWidget {
  final String videoLink;
  final UniqueKey newKey;

  MyVideoPlayer(this.videoLink, this.newKey): super(key: newKey); // passing Unique key to dispose old class instance and create new with new data

  @override
  _MyVideoPlayerState createState() => _MyVideoPlayerState();
} ...
  1. 将您正在播放视频的主 dart 文件的 VideoPlayer 实例替换为您之前创建的类,即 MyVideoPlayer 并传递 videoLink 和 UniqueKey()

  2. 现在,当您想要更改视频时,只需更新主 dart 文件的 setState(() {}) 内的 videoLink,然后通过完全处理旧的实例来创建一个新的 VideoPlayer 实例。

注意 - 这里的主要工作是由 UniqueKey() 完成的,通过传递 UniqueKey() 你是说颤动来创建这个特定类的新的唯一实例;

【讨论】:

    【解决方案3】:

    你可以使用它:

    @override
      void dispose() {
        if (_controller.value.isPlaying) _controller.pause();
        _controller.removeListener(_videoListener);
        _controller = null;
        super.dispose();
      }
    

    【讨论】:

    • 值得一提的是,这种方法也适用于 better_player 包,并进行了适当的语法修改。谢谢。
    【解决方案4】:

    我知道是以后了,但我想我找到了解决这个问题的一种方法。

    1.创建initPlayer()(我使用Provider创建)

      void initPlayer( {pause = false, update = false, updateUrl = ""} ) async {
      var isPlaying = false;
    
      if (controller == null) {
        controller = VideoPlayerController.file(File(url))..addListener(() {
        isPlaying = true;
        notifyListeners();
       })..initialize().then((value) => notifyListeners());
       controller.play();
       } else {
         print ("Controller is playing...");
       if (pause) {
        if (controller.value.isPlaying) {
          controller.pause();
        } else {
          controller.play();
        }
       }
       if (update && updateUrl != "") {
        final oldController = controller;
        await oldController.dispose();
        controller = VideoPlayerController.file(File(updateUrl))..addListener(() {
          isPlaying = true;
          notifyListeners();
           })..initialize().then((value) => notifyListeners());
          controller.play();
        }
      }
    }
    
    1. 在小部件中添加Actionsstartpausechange)。

            child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
          FlatButton(
            child: Text("Play Video"),
            color: Colors.red,
            onPressed: () {
              musicPlayerProvider.initPlayer();
            },
          ),
          FlatButton(
            child: Text("Stop Video"),
            color: Colors.pink,
            onPressed: () {
              musicPlayerProvider.initPlayer(pause: true);
            },
          ),
          FlatButton(
            child: Text("Change Video"),
            color: Colors.yellow,
            onPressed: () {
              musicPlayerProvider.initPlayer(update: true,updateUrl: 
                  "url");
            },
          ),
        ],),
      

    现在这个works 当然你可以做出改变。

    稍后我们需要使用addListener 方法(我猜)检查video 何时具有finished

    【讨论】:

      【解决方案5】:

      感谢某人from this link,这个解决了我的问题

      void dispose() {
              _controller.pause();
              _controller?.dispose();
              //ignore below
              audioPlayer.stop();
              audioPlayer?.dispose();
              super.dispose();
            }
      

      【讨论】:

        猜你喜欢
        • 2019-02-25
        • 1970-01-01
        • 1970-01-01
        • 2021-04-04
        • 2020-05-14
        • 2022-08-05
        • 2022-11-07
        • 2020-08-24
        • 1970-01-01
        相关资源
        最近更新 更多