YouTube Android API: YouTubePlayerFragment loading spinner - android

I am using the Android YouTube API samples to create a chromeless YouTube player in my app. I am having an issue that the buffering / loading progress bar carries on displaying over my video even after it has loaded and started playing. I can reproduce this in the FragmentDemoActivity sample with a couple of small modifications:
public class FragmentDemoActivity extends AppCompatActivity implements YouTubePlayer.OnInitializedListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragments_demo);
YouTubePlayerFragment youTubePlayerFragment =
(YouTubePlayerFragment) getFragmentManager().findFragmentById(R.id.youtube_fragment);
youTubePlayerFragment.initialize(DeveloperKey.DEVELOPER_KEY, this);
}
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer player,
boolean wasRestored) {
if (!wasRestored) {
player.setPlayerStyle(YouTubePlayer.PlayerStyle.CHROMELESS);
player.loadVideo("nCgQDjiotG0", 10);
}
}
#Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {}
}
I have changed FragmentDemoActivity to inherit from AppCompatActivity instead of YouTubeFailureRecoveryActivity, as the documentation says is fine to do. I have also changed the player style to be chromeless in onInitializationSuccess. Finally, I have changed cueVideo to loadVideo, just to trigger auto play.
This happens on multiple devices including Nexus 5X. I am using library version 1.2.2. No error is triggered in onInitializationFailure.
The video starts playing after buffering. The player is chromeless. However the buffering spinner never disappears. Is this a bug, or am I doing something I am not allowed to do?

I encountered this too, it really looks like a bug. Here is how I managed to work around it.
In your onInitializationSuccess, set a PlaybackEventListener on the player. Override the onBuffering and do something like this:
ViewGroup ytView = (ViewGroup)ytPlayerFragment.getView();
ProgressBar progressBar;
try {
// As of 2016-02-16, the ProgressBar is at position 0 -> 3 -> 2 in the view tree of the Youtube Player Fragment
ViewGroup child1 = (ViewGroup)ytView.getChildAt(0);
ViewGroup child2 = (ViewGroup)child1.getChildAt(3);
progressBar = (ProgressBar)child2.getChildAt(2);
} catch (Throwable t) {
// As its position may change, we fallback to looking for it
progressBar = findProgressBar(ytView);
// TODO I recommend reporting this problem so that you can update the code in the try branch: direct access is more efficient than searching for it
}
int visibility = isBuffering ? View.VISIBLE : View.INVISIBLE;
if (progressBar != null) {
progressBar.setVisibility(visibility);
// Note that you could store the ProgressBar instance somewhere from here, and use that later instead of accessing it again.
}
The findProgressBar method, used as a fallback just in case the YouTube code changes:
private ProgressBar findProgressBar(View view) {
if (view instanceof ProgressBar) {
return (ProgressBar)view;
} else if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup)view;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
ProgressBar res = findProgressBar(viewGroup.getChildAt(i));
if (res != null) return res;
}
}
return null;
}
This solution works perfectly fine for me, enabling the ProgressBar when the player is buffering and disabling it when it's not.
EDIT: If anyone using this solution discovers that this bug has been fixed or that the position of the ProgressBar has changed, please share so that I can edit my answer, thanks!

Related

Videos in RecyclerView: any way to prevent restarting when off-screen?

I have a RecyclerView with some video elements and they get restarted every time they get off-screen. I tried:
recyclerView.getRecycledViewPool().setMaxRecycledViews(RecyclerViewAdapter.TYPE_VIDEO, 0);
but no success. I also tried to do:
holder.setIsRecyclable(false)
inside my adapter, but videos still restart every time.
Is there any way to stop restarting videos, and somehow pause them and resume them once they are on screen again?
The videos are remote, not local. And I am using a class extending TextureView, not the Android's VideoView
Edit: I missunderstood the question. See original answer below.
I guess you have two possibilities:
Ugly, only possible if the list is not going to be too long™ and undermining the purpose of the recyclerview: use setItemViewCacheSize(int) to increase the number of viewholders that are cached to the number of videos you have and just pause and play during attach / detach.
much better: Store and restore the current playback timestamp of each video when the viewholder gets attached/dettached.
You can use an RecyclerView.OnChildAttachStateChangeListener that will be called whenever a view is attached / removed.
Do it like this:
mRecyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
#Override
public void onChildViewAttachedToWindow(View view) {
YourTextureView yourTextureView = (YourTextureView) view.findViewById(R.id.yourvideoviewid);
if (yourTextureView != null) {
// start your video
}
}
#Override
public void onChildViewDetachedFromWindow(View view) {
YourTextureView yourTextureView = (YourTextureView) view.findViewById(R.id.yourvideoviewid);
if (yourTextureView != null) {
// stop your video
}
}
});

YouTube Player View pausing video after each second

I understand that there are other similar questions asked. But they either have no solutions or the solutions provided are not working.
The player works fine in fullscreen mode but as a part of the layout contents, it keeps pausing and rebuffering.
Here is my code:
public class PlayerActivity extends YouTubeBaseActivity implements MediaPlayer.OnPreparedListener, YouTubePlayer.OnInitializedListener {
...
youTubePlayerView = (YouTubePlayerView) findViewById(R.id.player_youtube);
Button yt_player_button = (Button) findViewById(R.id.player_yt_play);
yt_player_button.setText("Click to play a Youtube video");
yt_player_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
youTubePlayerView.initialize(getString(R.string.youtube_api_key), PlayerActivity.this);
}
});
}
...
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean b) {
if (youTubePlayer == null)
return;
if (!b)
youTubePlayer.cueVideo("63kmMcHBQlA");
}
#Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {
}
YoutubePlayerView cannot be nested inside a ScrollView for whatever the reason.
It just doesn't work. I suggest that you create a fragment which pops up during the request for the Youtube video or creating a new intent with just the YoutubePlayerView (maybe fullscreen).
I couldn't find a reason as to why this is the case.
(Please do add it as an answer if you know why)
Using exo-player is a very good alternative too (If you can get the DASH Url's in a dynamic app. Then best of luck)

YoutubeApi loader doesn't disppear [duplicate]

I am using the Android YouTube API samples to create a chromeless YouTube player in my app. I am having an issue that the buffering / loading progress bar carries on displaying over my video even after it has loaded and started playing. I can reproduce this in the FragmentDemoActivity sample with a couple of small modifications:
public class FragmentDemoActivity extends AppCompatActivity implements YouTubePlayer.OnInitializedListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragments_demo);
YouTubePlayerFragment youTubePlayerFragment =
(YouTubePlayerFragment) getFragmentManager().findFragmentById(R.id.youtube_fragment);
youTubePlayerFragment.initialize(DeveloperKey.DEVELOPER_KEY, this);
}
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer player,
boolean wasRestored) {
if (!wasRestored) {
player.setPlayerStyle(YouTubePlayer.PlayerStyle.CHROMELESS);
player.loadVideo("nCgQDjiotG0", 10);
}
}
#Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {}
}
I have changed FragmentDemoActivity to inherit from AppCompatActivity instead of YouTubeFailureRecoveryActivity, as the documentation says is fine to do. I have also changed the player style to be chromeless in onInitializationSuccess. Finally, I have changed cueVideo to loadVideo, just to trigger auto play.
This happens on multiple devices including Nexus 5X. I am using library version 1.2.2. No error is triggered in onInitializationFailure.
The video starts playing after buffering. The player is chromeless. However the buffering spinner never disappears. Is this a bug, or am I doing something I am not allowed to do?
I encountered this too, it really looks like a bug. Here is how I managed to work around it.
In your onInitializationSuccess, set a PlaybackEventListener on the player. Override the onBuffering and do something like this:
ViewGroup ytView = (ViewGroup)ytPlayerFragment.getView();
ProgressBar progressBar;
try {
// As of 2016-02-16, the ProgressBar is at position 0 -> 3 -> 2 in the view tree of the Youtube Player Fragment
ViewGroup child1 = (ViewGroup)ytView.getChildAt(0);
ViewGroup child2 = (ViewGroup)child1.getChildAt(3);
progressBar = (ProgressBar)child2.getChildAt(2);
} catch (Throwable t) {
// As its position may change, we fallback to looking for it
progressBar = findProgressBar(ytView);
// TODO I recommend reporting this problem so that you can update the code in the try branch: direct access is more efficient than searching for it
}
int visibility = isBuffering ? View.VISIBLE : View.INVISIBLE;
if (progressBar != null) {
progressBar.setVisibility(visibility);
// Note that you could store the ProgressBar instance somewhere from here, and use that later instead of accessing it again.
}
The findProgressBar method, used as a fallback just in case the YouTube code changes:
private ProgressBar findProgressBar(View view) {
if (view instanceof ProgressBar) {
return (ProgressBar)view;
} else if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup)view;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
ProgressBar res = findProgressBar(viewGroup.getChildAt(i));
if (res != null) return res;
}
}
return null;
}
This solution works perfectly fine for me, enabling the ProgressBar when the player is buffering and disabling it when it's not.
EDIT: If anyone using this solution discovers that this bug has been fixed or that the position of the ProgressBar has changed, please share so that I can edit my answer, thanks!

VideoView is not displayed on a Fragment

I have a problem in running a video in Samsung S3(Android 4.1.1), the issue seems to be because the videoview is on a fragment because if I put it on and activity, it works.
Also I found out that if I turn on the GPU hardware acceleration on, the video works.
I have also a game made by drawing on a SurfaceView and that view doesn't work as well(only with GPU on)... The rest of the app content is displayed as it supposed to (buttons and other layouts).
I tested the app on Nexus S and on the emulator and it works fine, also on other devices..
Does anyone know what the problem could be?
Thank you!
And here is the code:
public class VideoFragment extends Fragment implements MediaPlayer.OnCompletionListener,
MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener {
private Video mVideo;
private VideoView mVideoView;
// The video position
private int mPosition;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.screen_video, container, false);
mVideoView = (VideoView) fragmentView.findViewById(R.id.VideoView);
return fragmentView;
}
#Override
public void onPause() {
super.onPause();
// Pause the video if it is playing
if (mVideoView.isPlaying()) {
mVideoView.pause();
}
// Save the current video position
mPosition = mVideoView.getCurrentPosition();
}
#Override
public void onResume() {
super.onResume();
mVideoView.setOnCompletionListener(this);
mVideoView.setOnPreparedListener(this);
mVideoView.setOnErrorListener(this);
mVideoView.setKeepScreenOn(true);
// Initialize the media controller
MediaController mediaController = new MediaController(getActivity());
mediaController.setMediaPlayer(mVideoView);
// Set-up the video view
mVideoView.setMediaController(mediaController);
mVideoView.requestFocus();
mVideoView.setVideoPath(mVideo.getUrl());
if (mVideoView != null) {
// Restore the video position
mVideoView.seekTo(mPosition);
mVideoView.requestFocus();
}
}
#Override
public void onDestroy() {
super.onDestroy();
// Clean-up
if (mVideoView != null) {
mVideoView.stopPlayback();
mVideoView = null;
}
}
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
Log.e("VIDEO PLAY", "end video play");
}
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
// Start the video view
mediaPlayer.start();
Log.e("VIDEO PLAY", "video ready for playback");
}
#Override
public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
Log.e("VIDEO PLAY", "error: " + i);
return true;
}
}
I don't think it's something related to context(Application or Activity).. because on all other devices the Video and the games are displayed..
Thanks for the help!
I have a similar problem, and i solved it changing:
MediaController mediaController = new MediaController(getActivity().getApplicationContext());
to this (In a fragmet):
MediaController mediaController = new MediaController(getActivity());
Hope this helps,...
EDIT
Look at this class
http://code.google.com/p/sinaweibo-honeycomb/source/browse/branches/sinaweibo-merged/src/com/lenovo/dll/SinaWeibo/VideoFragment.java?r=71
If hardware acceleration fixes your issue then I would enable it for that view/window on that device.
In general I've found that when code works on one device but not another it is typically caused by one of the following problems:
Bug in the manufacturer's API implementation
Different interpretation of the API by the manufacturer
Concurrency problem (e.g. race condition, improper synchronization) in your own code that happens to trigger more frequently on a particular device
As far as I can tell you seem to be using the UI thread appropriately so I would imagine your issue falls into one of the first two categories and you'll just need to work around it.
Move MediaController mediaController = new MediaController(getActivity()) from onResume() to onCreateView.

Buffering problems with android.media.MediaPlayer

I'm trying to implement a MediaPlayer on an Android app, but now I have two problems, which are not THE BIG SHOWSTOPPER but they are more then annoying and i have to fix it, just for me.
I implemented a async MediaPlayer+Controller to a Activity, which works fine.
My plan was to show also the percentage of the buffering on the MediaControl. This also works.
But now, after I can see the percentage, I saw a strange behaviour: if I seek to a position which is already in the buffer, the buffering will start from this position again. Is this a known and/or normal behavior/problem/feature ?
Here are more details:
I'm using the 2.2 SDK
This is how I implement it
public class Details extends Activity implements MediaPlayer.OnPreparedListener, MediaController.MediaPlayerControl {
[...]
private void setPosition(int currentPos ){
position = currentPos;
}
[...]
public void onCreate(Bundle savedInstanceState) {
[...]
mediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
#Override
public void onBufferingUpdate(MediaPlayer mp, int progress) {
setPosition(progress);
}
});
[...]
public int getBufferPercentage() {
return position;
}
[...]
public void seekTo(int i) {
General.mediaPlayer.seekTo(i);
}
}
What I expected after clicking on the seekbar
What I got
Is this normal?
This thread confirms that although a position is already buffered MediaPlayer sends a request to a server.

Categories

Resources