Flutter 颤振无法处理VideoPlayerController

Flutter 颤振无法处理VideoPlayerController,flutter,dart,dispose,Flutter,Dart,Dispose,在处理VideoPlayerController后,使用“后退”按钮时引发异常 我的VideoPlayer和VideoPlayerController设置如下: String url; var plan; _VideoPlayerScreenState(this.url,{this.plan}); Future<Null> OnWillPop(){ _controller.dispose(); if(plan!=null) Navigator.push(context,

在处理VideoPlayerController后,使用“后退”按钮时引发异常

我的VideoPlayer和VideoPlayerController设置如下:

 String url;
 var plan;
_VideoPlayerScreenState(this.url,{this.plan});

 Future<Null> OnWillPop(){

_controller.dispose();

if(plan!=null)
Navigator.push(context, MaterialPageRoute(builder: (context)=>
ListSession(plan :plan)));
else
  Navigator.push(context, MaterialPageRoute(builder: (context)=>
ListMoves()));

}
VideoPlayerController _controller;
Future<void> _initializeVideoPlayerFuture;

@override
void initState() {
 _controller = VideoPlayerController.network(
  url,
 );

// Initialize the controller and store the Future for later use.
_initializeVideoPlayerFuture = _controller.initialize();

// Use the controller to loop the video.
_controller.setLooping(true);
_controller.play();
super.initState();
}

@override
void dispose() {
 print("+++++++++++++++++++++++++++++++++++++++++++");
_controller.dispose();
 super.dispose();
}

 @override
 Widget build(BuildContext context) {
 return WillPopScope(onWillPop: OnWillPop,child:Scaffold(

   // Use a FutureBuilder to display a loading spinner while waiting for the
   // VideoPlayerController to finish initializing.
   body: FutureBuilder(
    future: _initializeVideoPlayerFuture,
    builder: (context, snapshot) {
      if (snapshot.connectionState == ConnectionState.done) {
        // If the VideoPlayerController has finished initialization, use
        // the data it provides to limit the aspect ratio of the video.
        return Center(
          child: AspectRatio(
            aspectRatio: _controller.value.aspectRatio,
            // Use the VideoPlayer widget to display the video.
            child: VideoPlayer(_controller),
          ),
        );
      } else {
        // If the VideoPlayerController is still initializing, show a
        // loading spinner.
        return Center(child: CircularProgressIndicator());
      }
    },
  ),
 ));
}

如何正确处置我的VideoPlayerController并合并后退按钮?

您可以复制下面的粘贴运行完整代码
并标记取消标记
Navigator.push
/
Navigator.pushReplacement
以检查效果
在您的情况下,您不需要处理
控制器
,因为
控制器
是此页面的本地部分,您只需执行
\u controller.pause()

您可以使用
Navigator。按
转到下一页意味着您将从下一页
弹出

如果您
dispose controller
并成功地将
controller
设置为
null
,当从下一页弹出时,您将得到一个错误,因为
initState
不会再次调用,
controller
不会再次初始化

如果使用
Navigator.pushReplacement
,将自动调用
dispose

您可以在演示代码中看到console show _controller.dispose

工作演示
ListMove
页面返回时,您可以看到视频仍然可以播放

完整代码

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';

void main() => runApp(VideoPlayerApp());

class VideoPlayerApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Video Player Demo',
      home: VideoPlayerScreen(),
    );
  }
}

class VideoPlayerScreen extends StatefulWidget {
  VideoPlayerScreen({Key key}) : super(key: key);

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

class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
  VideoPlayerController _controller;
  VideoPlayerController _oldController;
  Future<void> _initializeVideoPlayerFuture;

  @override
  void initState() {
    print("initState");
    // Create and store the VideoPlayerController. The VideoPlayerController
    // offers several different constructors to play videos from assets, files,
    // or the internet.
    _controller = VideoPlayerController.network(
      'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
    );

    // Initialize the controller and store the Future for later use.
    _initializeVideoPlayerFuture = _controller.initialize();

    // Use the controller to loop the video.
    _controller.setLooping(true);

    super.initState();
  }

  @override
  void dispose() {
    print("_controller.dispose");
    // Ensure disposing of the VideoPlayerController to free up resources.
    //_initializeVideoPlayerFuture = null;
    _controller.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        await _controller.pause();
        Navigator.push(
            context, MaterialPageRoute(builder: (context) => ListMoves()));

        /*Navigator.pushReplacement(
            context, MaterialPageRoute(builder: (context) => ListMoves()));*/
      },
      child: Scaffold(
        appBar: AppBar(
          title: Text('Butterfly Video'),
        ),
        // Use a FutureBuilder to display a loading spinner while waiting for the
        // VideoPlayerController to finish initializing.
        body: FutureBuilder(
          future: _initializeVideoPlayerFuture,
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.done) {
              // If the VideoPlayerController has finished initialization, use
              // the data it provides to limit the aspect ratio of the video.
              return AspectRatio(
                aspectRatio: _controller.value.aspectRatio,
                // Use the VideoPlayer widget to display the video.
                child: VideoPlayer(_controller),
              );
            } else {
              // If the VideoPlayerController is still initializing, show a
              // loading spinner.
              return Center(child: CircularProgressIndicator());
            }
          },
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            // Wrap the play or pause in a call to `setState`. This ensures the
            // correct icon is shown.
            setState(() {
              // If the video is playing, pause it.
              if (_controller.value.isPlaying) {
                _controller.pause();
              } else {
                // If the video is paused, play it.
                _controller.play();
              }
            });
          },
          // Display the correct icon depending on the state of the player.
          child: Icon(
            _controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
          ),
        ), // This trailing comma makes auto-formatting nicer for build methods.
      ),
    );
  }
}

class ListMoves extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('List Movies'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('Launch screen'),
          onPressed: () {},
        ),
      ),
    );
  }
}
导入'dart:async';
进口“包装:颤振/材料.省道”;
导入“package:video_player/video_player.dart”;
void main()=>runApp(VideoPlayerApp());
类VideoPlayerApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回材料PP(
标题:“视频播放器演示”,
主页:视频播放器屏幕(),
);
}
}
类VideoPlayerScreen扩展StatefulWidget{
视频播放器屏幕({Key}):超级(Key:Key);
@凌驾
_VideoPlayerScreenState createState()=>\u VideoPlayerScreenState();
}
类\u VideoPlayerScreenState扩展状态{
视频播放控制器\u控制器;
视频播放控制器(旧控制器);
未来(Future)初始设定未来玩家;;
@凌驾
void initState(){
打印(“初始状态”);
//创建并存储VideoPlayerController。VideoPlayerController
//提供多个不同的构造函数来播放来自资产、文件、,
//或者互联网。
_控制器=VideoPlayerController.network(
'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
);
//初始化控制器并存储将来使用的数据。
_initializeVideoPlayerFuture=_controller.initialize();
//使用控制器循环播放视频。
_控制器。设置循环(真);
super.initState();
}
@凌驾
无效处置(){
打印(“_controller.dispose”);
//确保处置VideoPlayerController以释放资源。
//_initializeVideoPlayerFuture=null;
_controller.dispose();
super.dispose();
}
@凌驾
小部件构建(构建上下文){
返回式示波器(
onWillPop:()异步{
等待控制器暂停();
导航器。推(
context,MaterialPageRoute(builder:(context)=>ListMoves());
/*导航器。更换(
context,MaterialPageRoute(builder:(context)=>ListMoves())*/
},
孩子:脚手架(
appBar:appBar(
标题:文本(“蝴蝶视频”),
),
//使用FutureBuilder在等待加载时显示加载微调器
//VideoPlayerController完成初始化。
正文:未来建设者(
未来:_initializevideoplayer未来,
生成器:(上下文,快照){
if(snapshot.connectionState==connectionState.done){
//如果VideoPlayerController已完成初始化,请使用
//它提供的数据用于限制视频的纵横比。
返回AspectRatio(
aspectRatio:_controller.value.aspectRatio,
//使用VideoPlayer小部件显示视频。
子项:视频播放器(_控制器),
);
}否则{
//如果VideoPlayerController仍在初始化,则显示
//加载旋转器。
返回中心(子项:CircularProgressIndicator());
}
},
),
浮动操作按钮:浮动操作按钮(
已按下:(){
//在调用“setState”时结束播放或暂停。这样可以确保
//显示正确的图标。
设置状态(){
//如果正在播放视频,请将其暂停。
if(_controller.value.isPlaying){
_controller.pause();
}否则{
//如果视频暂停,请播放它。
_controller.play();
}
});
},
//根据播放机的状态显示正确的图标。
子:图标(
_controller.value.isplay?图标。暂停:图标。播放箭头,
),
),//此尾随逗号使生成方法的自动格式设置更方便。
),
);
}
}
类ListMoves扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回脚手架(
appBar:appBar(
标题:文本(“电影列表”),
),
正文:中(
孩子:升起按钮(
子项:文本(“启动屏幕”),
按下:(){},
),
),
);
}
}

请看一下我的答案
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';

void main() => runApp(VideoPlayerApp());

class VideoPlayerApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Video Player Demo',
      home: VideoPlayerScreen(),
    );
  }
}

class VideoPlayerScreen extends StatefulWidget {
  VideoPlayerScreen({Key key}) : super(key: key);

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

class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
  VideoPlayerController _controller;
  VideoPlayerController _oldController;
  Future<void> _initializeVideoPlayerFuture;

  @override
  void initState() {
    print("initState");
    // Create and store the VideoPlayerController. The VideoPlayerController
    // offers several different constructors to play videos from assets, files,
    // or the internet.
    _controller = VideoPlayerController.network(
      'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
    );

    // Initialize the controller and store the Future for later use.
    _initializeVideoPlayerFuture = _controller.initialize();

    // Use the controller to loop the video.
    _controller.setLooping(true);

    super.initState();
  }

  @override
  void dispose() {
    print("_controller.dispose");
    // Ensure disposing of the VideoPlayerController to free up resources.
    //_initializeVideoPlayerFuture = null;
    _controller.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        await _controller.pause();
        Navigator.push(
            context, MaterialPageRoute(builder: (context) => ListMoves()));

        /*Navigator.pushReplacement(
            context, MaterialPageRoute(builder: (context) => ListMoves()));*/
      },
      child: Scaffold(
        appBar: AppBar(
          title: Text('Butterfly Video'),
        ),
        // Use a FutureBuilder to display a loading spinner while waiting for the
        // VideoPlayerController to finish initializing.
        body: FutureBuilder(
          future: _initializeVideoPlayerFuture,
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.done) {
              // If the VideoPlayerController has finished initialization, use
              // the data it provides to limit the aspect ratio of the video.
              return AspectRatio(
                aspectRatio: _controller.value.aspectRatio,
                // Use the VideoPlayer widget to display the video.
                child: VideoPlayer(_controller),
              );
            } else {
              // If the VideoPlayerController is still initializing, show a
              // loading spinner.
              return Center(child: CircularProgressIndicator());
            }
          },
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            // Wrap the play or pause in a call to `setState`. This ensures the
            // correct icon is shown.
            setState(() {
              // If the video is playing, pause it.
              if (_controller.value.isPlaying) {
                _controller.pause();
              } else {
                // If the video is paused, play it.
                _controller.play();
              }
            });
          },
          // Display the correct icon depending on the state of the player.
          child: Icon(
            _controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
          ),
        ), // This trailing comma makes auto-formatting nicer for build methods.
      ),
    );
  }
}

class ListMoves extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('List Movies'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('Launch screen'),
          onPressed: () {},
        ),
      ),
    );
  }
}