[英]Flutter video_player dispose
I'm using provider
with video_player
to manage the state.我正在使用带有
video_player
的provider
来管理 state。
VideoProvider has: VideoProvider 有:
videoPlayerController = VideoPlayerController.network(...);
which I frequently change when the user switches to a new video (same screen).当用户切换到新视频(同一屏幕)时,我经常更改它。 If I directly assign a new
VideoPlayerController.network(...)
into the videoPlayerController
, the old video will still play and you can hear the sound.如果我直接将 new
VideoPlayerController.network(...)
分配给videoPlayerController
,旧视频仍会播放并且您可以听到声音。 The workaround is to videoPlayerController.pause()
then assign a new VideoPlayerCOntroller.network
afterwards.解决方法是使用
videoPlayerController.pause()
然后分配一个新的VideoPlayerCOntroller.network
。
Is the previous Video being disposed by GC?以前的视频是否正在被 GC 处理? Are there any performance issues with this?
这有什么性能问题吗? I want to get rid of the previous video and the resources used before switching to a new one.
我想在切换到新视频之前摆脱以前的视频和使用的资源。 I can't
videoPlayerController.dispose()
before switching because it causes an error.我不能在切换之前使用
videoPlayerController.dispose()
,因为它会导致错误。
When you call dispose
your controller is still being used by VideoPlayer widget.当您调用
dispose
时,您的 controller 仍在被VideoPlayer小部件使用。 First, you need to make sure that it's not used anymore (setting controller in state to null) and AFTER that you call dispose.首先,您需要确保不再使用它(将 state 中的 controller 设置为 null)并在调用 dispose 之后。
I'm not sure about your state management via Provider, but I'll give you an example how to do this with regular State.我不确定你的 state 通过 Provider 管理,但我会给你一个例子,如何使用常规 State 做到这一点。
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;
});
}
}
I know its late but this will help others with same problem.我知道它很晚,但这将帮助其他有同样问题的人。
I had same issue, i wanted to change Video when user selects new video from list, after researching so much i finally created a solution by myself.我有同样的问题,当用户从列表中选择新视频时,我想更改视频,经过大量研究,我终于自己创建了一个解决方案。
Follows the below step and you can video video in Video Player in same screen按照以下步骤,您可以在同一屏幕上的视频播放器中播放视频
StatefulWidget
class containing VideoPlayer
and initialize the videoPlayerController in init
method.VideoPlayer
的StatefulWidget
class 并在init
方法中初始化 videoPlayerController。 Suppose you created a StatefulWidget class named MyVideoPlayer then in constructor accept two variable, ie, i> String videoLink ii> UniqueKey() Note - You have to pass UniqueKey() to the super of this class, example,注意- 您必须将 UniqueKey() 传递给此 class 的上级,例如,
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();
} ...
Replace your VideoPlayer
instance of main dart file where you are playing video with your previously created class ie, MyVideoPlayer
and pass videoLink and UniqueKey()
.将您正在播放视频的主 dart 文件的
VideoPlayer
实例替换为您之前创建的 class 即MyVideoPlayer
并传递 videoLink 和UniqueKey()
。
Now whenever you want to change the video just update videoLink inside setState(() {})
of your main dart file and after that a new VideoPlayer instance is created by disposing the old one totally.现在,每当您想更改视频时,只需更新主 dart 文件的
setState(() {})
内的 videoLink,然后通过完全处理旧的 VideoPlayer 实例创建一个新的 VideoPlayer 实例。
Note - Here the main work is done by UniqueKey(), by passing UniqueKey() you are saying flutter to create a new unique instance of this particular class;注意 - 这里的主要工作是由 UniqueKey() 完成的,通过传递 UniqueKey() 你说 flutter 来创建这个特定 class 的新唯一实例;
You can use that:你可以使用它:
@override
void dispose() {
if (_controller.value.isPlaying) _controller.pause();
_controller.removeListener(_videoListener);
_controller = null;
super.dispose();
}
I know is later but I think i found one way to fix this.我知道是以后,但我想我找到了解决这个问题的一种方法。
1.Create initPlayer()
(I've created using Provider
) 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();
}
}
}
Add Actions
( start
, pause
change
) in the widget.在小部件中添加
Actions
( start
、 pause
change
)。
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"); }, ), ],),
For now this works
but of course you can make changes.目前这
works
,但您当然可以进行更改。
Later we need to check when the video
has finished
using addListener
method ( I guess ).稍后我们需要使用
addListener
方法检查video
何时finished
(我猜)。
This one fixed my issue thanks to someone from this link感谢此链接中的某人,这解决了我的问题
void dispose() {
_controller.pause();
_controller?.dispose();
//ignore below
audioPlayer.stop();
audioPlayer?.dispose();
super.dispose();
}
I was making a-la Instagram grid view.我正在制作 Instagram 网格视图。 Every time when I picked a new file I should update my thumbnail.
每次我选择一个新文件时,我都应该更新我的缩略图。 But my Stateful widget was not recognizing the update.
但是我的有状态小部件无法识别更新。 The dispose method wasn't launching.
dispose 方法没有启动。
Finally I came up with this.最后我想到了这个。 Hope this will help someone.
希望这会对某人有所帮助。
class _SelectedVideo extends StatefulWidget {
const _SelectedVideo({
Key? key,
required this.file,
}) : super(key: key);
final File file;
@override
State<_SelectedVideo> createState() => _SelectedVideoState();
}
class _SelectedVideoState extends State<_SelectedVideo> {
VideoPlayerController? _controller;
void _initVideoPlayer(File file) async {
_controller = VideoPlayerController.file(
file,
);
await _controller!.initialize();
_controller!.setVolume(0);
_controller!.play();
setState(() {});
}
@override
void initState() {
super.initState();
_initVideoPlayer(widget.file);
}
@override
void didUpdateWidget(covariant _SelectedVideo oldWidget) {
// I'm disposing controller all the time when widget updates
_controller?.dispose();
_initVideoPlayer(widget.file);
super.didUpdateWidget(oldWidget);
}
@override
void dispose() {
_controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
if (_controller == null) return Container();
return Container(
color: Colors.black,
height: 375,
width: double.infinity,
child: FittedBox(
fit: BoxFit.cover,
clipBehavior: Clip.hardEdge,
child: SizedBox(
width: _controller!.value.size.width,
height: _controller!.value.size.height,
child: AspectRatio(
aspectRatio: _controller!.value.aspectRatio,
child: VideoPlayer(_controller!),
),
),
),
);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.