我正在将provider
与video_player
一起使用来管理状态。
VideoProvider具有:
videoPlayerController = VideoPlayerController.network(...);
当用户切换到新视频(同一屏幕)时,我经常更改。如果我直接将新的VideoPlayerController.network(...)
分配给videoPlayerController
,则旧视频仍会播放,您可以听到声音。解决方法是先videoPlayerController.pause()
,然后再分配新的VideoPlayerCOntroller.network
。
上一个视频是否已由GC处理?这有任何性能问题吗?我想摆脱以前的视频和切换到新视频之前使用的资源。切换之前,我无法videoPlayerController.dispose()
,因为它会导致错误。
答案 0 :(得分:2)
调用dispose
时, VideoPlayer 小部件仍在使用您的控制器。首先,您需要确保不再使用它(将状态为controller的控制器设置为null),然后再调用dispose。
我不确定您是如何通过提供商进行状态管理的,但我将举例说明如何使用常规状态。
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;
});
}
}
答案 1 :(得分:0)
我知道是以后,但是我想我找到了一种解决此问题的方法。
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();
}
}
}
在窗口小部件中添加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");
},
),
],),
暂时works
,但是您当然可以进行更改。
稍后我们需要使用video
方法检查finished
是否具有addListener
。(我猜是)。
答案 2 :(得分:0)
我知道它来晚了,但这会帮助其他有相同问题的人。
我遇到了同样的问题,当用户从列表中选择新视频时,我想更改视频,在进行了如此多的研究之后,我终于自己创建了一个解决方案。
按照以下步骤操作,您可以在同一屏幕的视频播放器中录制视频
StatefulWidget
的{{1}}类,并使用VideoPlayer
方法初始化videoPlayerController。
假设您创建了一个名为MyVideoPlayer的StatefulWidget类,然后在构造函数中接受两个变量,即
i>字符串videoLink
ii> UniqueKey()注意-您必须将UniqueKey()传递给此类的上级,例如
init
使用先前创建的类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();
} ...
替换要在其中播放视频的主dart文件的VideoPlayer
实例,并传递videoLink和MyVideoPlayer
。
现在,只要您想更改视频,只需在主dart文件的UniqueKey()
中更新videoLink,然后通过完全丢弃旧视频实例来创建一个新的VideoPlayer实例。
注意-这里的主要工作是由UniqueKey()完成的,通过传递UniqueKey(),您可以说是颤抖地创建了该特定类的新的唯一实例;
答案 3 :(得分:0)
您可以使用它:
@override
void dispose() {
if (_controller.value.isPlaying) _controller.pause();
_controller.removeListener(_videoListener);
_controller = null;
super.dispose();
}