I'm trying to use a YouTubePlayerSupportFragment
in a ListView
item. The ListView
is inside a Fragment
that's in an Activity
. Since there are nested fragments I'm using the getChildFragmentManager()
method to try to find the fragment from the XML layout. Here is the code.
Java
convertView = inflater.inflate(R.layout.youtube_post_layout, null);
YouTubePlayerSupportFragment youTubePlayerFragment = (YouTubePlayerSupportFragment) getChildFragmentManager().findFragmentById(R.id.youtube_video);
if (youTubePlayerFragment == null) {
Log.i("YouTube", "player is null");
} else {
Log.i("YouTube", youTubePlayerFragment.toString());
}
XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<include layout="@layout/post_base_layout" />
<fragment
android:name="com.google.android.youtube.player.YouTubePlayerSupportFragment"
android:id="@+id/youtube_video"
android:layout_width="match_parent"
android:layout_height="240dp"
android:layout_marginLeft="62dp"
android:layout_marginRight="32dp"
android:background="@color/light_grey"
android:cropToPadding="true"
android:padding="1dp"
android:scaleType="centerCrop" />
<include layout="@layout/post_bottom_layout" />
</LinearLayout>
The problem is that when I try to create the fragment by doing findFragmentById()
to get it from the XML, it returns null, and that's what is posted to the stack trace.
I'm trying to follow the YouTube API samples and make the changes needed for nested fragments but I can't find out what's causing the issue.
There are problems with the whole approach you have taken.
First, inflating child fragments directly from an XML is not supported. When nesting fragments, you must add them dinamically using getChildFragmentManager
in the parent fragment.
Second, even if it worked (and it might in some cases), you have inflated the view but not added it to the actual fragment's layout. That's what the second and third parameters in the inflate
method are there for. The FragmentManager
will look for fragment in its current layout, or event in the backstack, but can't find fragments inflated in a random XML and never put to use.
Finally, and most important, you should never add fragments as items in an ListView
. Fragments expect to have a lifecycle tied to the Activity they are in, while a ListView
, or any AdapterView
in general, will create, destroy and recycle its children as needed.
Possible solutions:
How many videos do you need on your list? If there are not many of them, a ScrollView+LinearLayout might actually be the easiest solution.
If you really need View recycling, maybe you can do without live video in every row? Consider using a YouTubeThumbnailView in your rows, then redirecting your user to another activity / loading a the video in a single YoutubeFragment
located outside of the list on your layout.
If you definitely want videos playing directly on every row in the list, you will need to use YoutubePlayerView instead of fragments on your row layout. In this case, read the documentation carefully, because you will need to handle the video initialization and view recycling yourself.
your app will crash When you try to inflate view with same Fragment
every ListView
item (As duplication in fragment id like this quiz)
There Two solution (one of them from @ivagarz answer) :
1- You can display only one youtube video Using YouTubePlayerView
above your ListView
into your Activity
layout But your Activity
Must extends YouTubeBaseActivity
Like YouTube Android Player API Doc (I Think this Solution will not help you to solve your problem)
2- you can use YouTubeThumbnailView
to Display youtube Thumbnail Image of Video for Every Item into ListView
with youtube player button over youtube Thumbnail Image Used to Display Video.
Like The next Picture :
When User click on youtube player button, You Have two ways:
First option using YouTubePlayerSupportFragment
: you can replacing YouTubeThumbnailView
with YouTubePlayerSupportFragment
If you take This Option you must :
A- add YouTubePlayerSupportFragment
programmatically on the Fly (to avoid duplication in Fragment
Id).
B- Display Only one Video into your ListView
As answer of this Question.
Ex:
list_item.xml
layout for ListView
item:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/parent_relativeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.google.android.youtube.player.YouTubeThumbnailView
android:id="@+id/youtube_thumbnail"
android:layout_width="fill_parent"
android:layout_height="250dp"
android:scaleType="centerCrop"
android:visibility="gone"/>
<RelativeLayout android:id="@+id/relativeLayout_over_youtube_thumbnail"
android:layout_width="fill_parent"
android:layout_height="250dp"
android:background="@color/color_background_transparent"
android:visibility="gone">
<ImageView android:id="@+id/btnYoutube_player"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="center"
android:src="@drawable/youtube_player"/>
</RelativeLayout>
</RelativeLayout>
in getView
mehtod of ListView
adapter:
public View getView(int position, View convertView, ViewGroup parent) {
convertView = inflator.inflate(R.layout.list_item.xml, parent, false);
final RelativeLayout relativeLayoutOverYouTubeThumbnailView = (RelativeLayout) convertView.findViewById(R.id.relativeLayout_over_youtube_thumbnail);
final YouTubeThumbnailView youTubeThumbnailView = (YouTubeThumbnailView) convertView.findViewById(R.id.youtube_thumbnail);
// get parent relative layout
RelativeLayout parentRelativeLayout = (RelativeLayout) convertView.findViewById(R.id.parent_relativeLayout);
// then create dynamic FrameLayout
FrameLayout.LayoutParams dynamicFrameLayoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
final FrameLayout dynamicFrameLayout = new FrameLayout(ctx);
dynamicFrameLayout.setId(Different_ID);
dynamicFrameLayout.setLayoutParams(dynamicFrameLayoutParams);
// then add dynamic FrameLayout as children in parent relative layout
parentRelativeLayout.addView(dynamicFrameLayout);
ImageView youtubePlayerButton = (ImageView) convertView.findViewById(R.id.btnYoutube_player);
youtubePlayerButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
View parentView = (View) v.getParent().getParent();
YouTubeThumbnailView youTubeThumbnailView = (YouTubeThumbnailView) parentView.findViewById(R.id.youtube_thumbnail);
RelativeLayout relativeLayoutOverYouTubeThumbnailView = (RelativeLayout) parentView.findViewById(R.id.relativeLayout_over_youtube_thumbnail);
youTubeThumbnailView.setVisibility(View.GONE);
relativeLayoutOverYouTubeThumbnailView.setVisibility(View.GONE);
YouTubeFragment youTubeFragment = new YouTubeFragment();
youTubeFragment.youTubeFragmentInitialize(VideoID, youTubeFragment, parentView);
getSupportFragmentManager()
.beginTransaction()
.replace(dynamicFrameLayout.getId(), youTubeFragment)
.commit();
}
});
final YouTubeThumbnailLoader.OnThumbnailLoadedListener onThumbnailLoadedListener = new YouTubeThumbnailLoader.OnThumbnailLoadedListener(){
@Override
public void onThumbnailError(YouTubeThumbnailView youTubeThumbnailView, YouTubeThumbnailLoader.ErrorReason errorReason) {
}
@Override
public void onThumbnailLoaded(YouTubeThumbnailView youTubeThumbnailView, String s) {
loadingImage.setVisibility(View.GONE);
youTubeThumbnailView.setVisibility(View.VISIBLE);
relativeLayoutOverYouTubeThumbnailView.setVisibility(View.VISIBLE);
}
};
youTubeThumbnailView.initialize(API_KEY, new YouTubeThumbnailView.OnInitializedListener() {
@Override
public void onInitializationSuccess(YouTubeThumbnailView youTubeThumbnailView, YouTubeThumbnailLoader youTubeThumbnailLoader) {
youTubeThumbnailLoader.setVideo(VideoID);
youTubeThumbnailLoader.setOnThumbnailLoadedListener(onThumbnailLoadedListener);
}
@Override
public void onInitializationFailure(YouTubeThumbnailView youTubeThumbnailView, YouTubeInitializationResult youTubeInitializationResult) {
}
});
}
I was created my own Fragment
extends from YouTubePlayerSupportFragment
:
public class YouTubeFragment extends YouTubePlayerSupportFragment {
public void youTubeFragmentInitialize(final String videoId, final YouTubeFragment fragment, final View parent) {
fragment.initialize(apiKey, new YouTubePlayer.OnInitializedListener() {
@Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, final YouTubePlayer youTubePlayer, boolean wasRestored) {
youTubePlayer.setShowFullscreenButton(false);
if (!wasRestored) {
youTubePlayer.loadVideo(videoId);
}
}
@Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {
Log.e("app", youTubeInitializationResult.toString());
}
});
}
}
Second option using YouTubeStandalonePlayer
or creating your Own Activity
extends YouTubeBaseActivity
: Just when User click on youtube player button, you can create an Intent to open new activity to display Video
Intent intent = YouTubeStandalonePlayer.createVideoIntent(context, YOUR_DEVELOPER_KEY, VIDEO_ID);
startActivity(intent);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With