Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/video_player/video_player_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.12.1

* Fixes a [bug](https://github.com/flutter/flutter/issues/190739) where building the view for a disposed player threw a `StateError` instead of building an empty view.

## 2.12.0

* Fixes a [bug](https://github.com/flutter/flutter/issues/176575) where some videos report an incorrect duration when initialized without a video duration.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,16 @@ class AndroidVideoPlayer extends VideoPlayerPlatform {
@override
Widget buildViewWithOptions(VideoViewOptions options) {
final int playerId = options.playerId;
final VideoPlayerViewState viewState = _playerWith(id: playerId).viewState;
// Disposal and the next frame are not synchronized: a widget holding this player can be rebuilt
// after the player is gone (an AnimatedSwitcher transition, or a rebuild triggered by a
// configuration change once the platform has reclaimed the player). Build an empty view rather
// than throwing, since a build method that throws leaves the widget permanently broken.
final _PlayerInstance? player = _players[playerId];
if (player == null) {
return const SizedBox.shrink();
}

return switch (viewState) {
return switch (player.viewState) {
VideoPlayerTextureViewState(:final int textureId) => Texture(textureId: textureId),
VideoPlayerPlatformViewState() => PlatformViewPlayer(playerId: playerId),
};
Expand Down
2 changes: 1 addition & 1 deletion packages/video_player/video_player_android/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: video_player_android
description: Android implementation of the video_player plugin.
repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player_android
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22
version: 2.12.0
version: 2.12.1

environment:
sdk: ^3.12.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,16 @@ void main() {
verify(api.dispose(1));
});

test('buildViewWithOptions returns an empty widget after the player is disposed', () async {
final (AndroidVideoPlayer player, _, _) = setUpMockPlayer(playerId: 1, textureId: 100);
await player.dispose(1);

// A disposed player can still be built: the widget stays mounted through the frame that
// follows disposal (an AnimatedSwitcher transition, or a rebuild from a configuration
// change), so building must degrade to an empty view rather than throw.
expect(player.buildViewWithOptions(const VideoViewOptions(playerId: 1)), isA<SizedBox>());
});

test('create with asset', () async {
final (AndroidVideoPlayer player, MockAndroidVideoPlayerApi api, _) = setUpMockPlayer(
playerId: 1,
Expand Down
4 changes: 4 additions & 0 deletions packages/video_player/video_player_avfoundation/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.11.1

* Fixes a [bug](https://github.com/flutter/flutter/issues/190739) where building the view for a disposed player threw a `StateError` instead of building an empty view.

## 2.11.0

* Implements `setPreventsDisplaySleepDuringVideoPlayback` using
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,16 @@ class AVFoundationVideoPlayer extends VideoPlayerPlatform {
@override
Widget buildViewWithOptions(VideoViewOptions options) {
final int playerId = options.playerId;
final VideoPlayerViewState viewState = _playerWith(id: playerId).viewState;
// Disposal and the next frame are not synchronized: a widget holding this player can be rebuilt
// after the player is gone (an AnimatedSwitcher transition, or a rebuild triggered by a
// configuration change once the platform has reclaimed the player). Build an empty view rather
// than throwing, since a build method that throws leaves the widget permanently broken.
final _PlayerInstance? player = _players[playerId];
if (player == null) {
return const SizedBox.shrink();
}

return switch (viewState) {
return switch (player.viewState) {
VideoPlayerTextureViewState(:final int textureId) => Texture(textureId: textureId),
VideoPlayerPlatformViewState() => _buildPlatformView(playerId),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: video_player_avfoundation
description: iOS and macOS implementation of the video_player plugin.
repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player_avfoundation
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22
version: 2.11.0
version: 2.11.1

environment:
sdk: ^3.10.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ void main() {
verify(playerApi.dispose());
});

test('buildViewWithOptions returns an empty widget after the player is disposed', () async {
final (AVFoundationVideoPlayer player, _, _) = setUpMockPlayer(playerId: 1, textureId: 101);
await player.dispose(1);

// A disposed player can still be built: the widget stays mounted through the frame that
// follows disposal (an AnimatedSwitcher transition, or a rebuild from a configuration
// change), so building must degrade to an empty view rather than throw.
expect(player.buildViewWithOptions(const VideoViewOptions(playerId: 1)), isA<SizedBox>());
});

test('create with asset', () async {
final (AVFoundationVideoPlayer player, MockAVFoundationVideoPlayerApi api, _) =
setUpMockPlayer(playerId: 1, textureId: 101);
Expand Down