Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Video stops playing after scroll in ListView #174

Closed
marcinsiedlik opened this issue Mar 9, 2020 · 4 comments
Closed

[BUG] Video stops playing after scroll in ListView #174

marcinsiedlik opened this issue Mar 9, 2020 · 4 comments
Assignees
Labels
bug Something isn't working

Comments

@marcinsiedlik
Copy link

Describe the bug
I had an YoutubePlayer in ListView. When i scroll down to the point when player is no longer visible, it stops the playback, listener stop working and i get this log messages:

After scrolling down
On Android:

D/        (21918): PlayerBase::stop() from IPlayer
D/AudioTrack(21918): stop() called with 395524 frames delivered
W/cr_MediaCodecBridge(21918): Releasing: OMX.qcom.video.decoder.vp9
D/SurfaceUtils(21918): disconnecting from surface 0x7beff50010, reason disconnectFromSurface
W/cr_MediaCodecBridge(21918): Codec released
E/chromium(21918): [ERROR:aw_browser_terminator.cc(125)] Renderer process (23049) crash detected (code -1).

On iOS:
nothing

After scrolling up
On Android:

I/chromium(24489): [INFO:CONSOLE(1)] "Uncaught ReferenceError: play is not defined", source: https://www.youtube.com/ (1)
I/chromium(24489): [INFO:CONSOLE(139)] "Unrecognized feature: 'picture-in-picture'.", source: https://s.ytimg.com/yts/jsbin/www-widgetapi-vflkAsU_-/www-widgetapi.js (139)

On iOS:

[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: PlatformException(evaluateJavaScript_failed, Failed evaluating JavaScript, JavaScript string was: 'play()'
Error Domain=WKErrorDomain Code=4 "Wystąpił wyjątek JavaScript" UserInfo={WKJavaScriptExceptionLineNumber=1, WKJavaScriptExceptionMessage=ReferenceError: Can't find variable: play, WKJavaScriptExceptionColumnNumber=5, WKJavaScriptExceptionSourceURL=about:blank, NSLocalizedDescription=Wystąpił wyjątek JavaScript})
#0      StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:569:7)
#1      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:156:18)
<asynchronous suspension>
#2      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:329:12)
#3      MethodChannelWebViewPlatform.evaluateJavascript (package:webview_media/src/webview_method_channel.dart:113:21)
#4      WebViewController.evaluateJavascript (package:webview_media/webview_flutter.dart:684:39)
#5      YoutubePlayerController._callMethod (package:youtube_player_flutter/src/utils/youtube_player_controller.dart:178:32)
#6      YoutubePlayerController.play (package:youtube_player_flutter/src/utils/youtube_player_controller.dart:189:18)
#7      _YoutubePlayerState.listener (package:youtube_player_flutter/src/player/youtube_player.dart:214:49)
#8      ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:206:21)
#9      ValueNotifier.value= (package:flutter/src/foundation/change_notifier.dart:273:5)
#10     YoutubePlayerController.updateValue (package:youtube_player_flutter/src/utils/youtube_player_controller.dart:186:52)
#11     _RawYoutubePlayerState.build.<anonymous closure>.<anonymous closure> (package:youtube_player_flutter/src/player/raw_youtube_player.dart:223:26)
#12     _rootRunUnary (dart:async/zone.dart:1134:38)
#13     _CustomZone.runUnary (dart:async/zone.dart:1031:19)
#14     _FutureListener.handleValue (dart:async/future_impl.dart:140:18)
#15     Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:682:45)
#16     Future._propagateToListeners (dart:async/future_impl.dart:711:32)
#17     Future._completeWithValue (dart:async/future_impl.dart:526:5)
#18     Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:556:7)
#19     _rootRun (dart:async/zone.dart:1126:13)
#20     _CustomZone.run (dart:async/zone.dart:1023:19)
#21     _CustomZone.runGuarded (dart:async/zone.dart:925:7)
#22     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:965:23)
#23     _microtaskLoop (dart:async/schedule_microtask.dart:43:21)
#24     _startMicrotaskLoop (dart:async/schedule_microtask.dart:52:5)

My code:
Widget:

Widget _buildYoutubeHeader(BuildContext context, DeviceDetailsNotifier notifier, UiDeviceDetails data) {
    return data.videoId != null
        ? YoutubePlayer(
            controller: notifier.youtubeController,
            aspectRatio: 1 / 1,
            progressIndicatorColor: AppColors.colorPrimary,
            liveUIColor: AppColors.colorPrimary,
            showVideoProgressIndicator: true,
            progressColors: const ProgressBarColors(
              backgroundColor: AppColors.colorEmptyInput,
              playedColor: AppColors.colorPrimary,
            ),
          )
        : PlaceholderImage(
            networkUrl: data.imageUrl,
          );
  }

Controller initialization in notifier:

void _setupYoutubeController(String videoId) {
    if (videoId != null) {
      youtubeController = YoutubePlayerController(
        initialVideoId: videoId,
        flags: YoutubePlayerFlags(
          forceHideAnnotation: true,
          captionLanguage: networkHeaders.languageCodeValue,
        ),
      );
    }
  }

Technical Details:

  • Version ^6.1.0+4
  • Device: Android: Redmi Note 5 (Android 9), iOS: iPhone 6s (iOS 11.4.1)
@marcinsiedlik marcinsiedlik added the bug Something isn't working label Mar 9, 2020
@TheBestMoshe
Copy link

I would guess this is happening because flutter reuses widgets in a ListView

@marcinsiedlik
Copy link
Author

marcinsiedlik commented Mar 18, 2020

I would guess this is happening because flutter reuses widgets in a ListView

You're right, as very ugly walkaround i replace player with empty container and call reset on controller when user scrolls down and putting new player and seeking to last position when user scrolls back.

@ClemaX
Copy link

ClemaX commented Apr 17, 2020

I guess you're using ListView.builder, which is recycling and building on demand. Maybe you can achieve what you want by using a simple ListView, but keep in mind this is only viable on small lists...

@artur-tamazian
Copy link

I was able to fix it by wrapping the list item that contains the YT player in a stateful widget with AutomaticKeepAliveClientMixin:

class AliveListItem extends StatefulWidget {
  final Widget child;

  const AliveListItem(this.child, {Key? key}) : super(key: key);

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

class _AliveListItemState extends State<AliveListItem> with AutomaticKeepAliveClientMixin<AliveListItem> {

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return widget.child;
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  bool get wantKeepAlive => true;
}

Usage

ListView(
    children: [
        ....
        AliveListItem(_buildYoutubePlayer()),
        ....
    ],
 )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants