I want to load a YoutubePlayer in a fragment using the YouTubePlayerFragment from the API
The .xml file of the my fragment is:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- VIDEO CONTENT -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:paddingLeft="@dimen/layout_horizontal_margin"
android:paddingRight="@dimen/layout_horizontal_margin"
android:paddingTop="@dimen/layout_vertical_margin"
android:paddingBottom="@dimen/layout_vertical_margin" >
<fragment
android:name="com.google.android.youtube.player.YouTubePlayerFragment"
android:id="@+id/youtubeplayer_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
<!-- LYRIC CONTENT -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2" >
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@drawable/af_background"
android:layout_centerInParent="true" />
<!-- TEXT STRUCTURE -->
<LinearLayout
android:orientation="vertical"
android:id="@+id/lyric_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true" >
<LinearLayout
android:id="@+id/start_layout"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_gravity="center_horizontal"
android:layout_centerInParent="true">
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/lyric_margin_top"
android:gravity="center"
android:text="@string/textTitle2"
android:textSize="@dimen/lyric_size"
android:textIsSelectable="false"/>
</LinearLayout>
</LinearLayout>
<!-- FRONT BACKGROUND -->
<ImageView
android:id="@+id/high_part_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:src="@drawable/af_background_up_side"
android:scaleType="fitStart"/>
<ImageView
android:id="@+id/low_part_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:src="@drawable/af_background_down_side"
android:scaleType="fitEnd"/>
</RelativeLayout>
</LinearLayout>
As you can see, I've added a
Now the Fragment that loads this .xml is:
public class MyFragment extends Fragment{
/**
* The fragment argument representing the item ID that this fragment
* represents.
*/
public static final String ARG_ITEM_ID = "item_id";
/**
* The content this fragment is presenting.
*/
private Items.ItemList mItem;
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public MyFragment() {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments().containsKey(ARG_ITEM_ID)) {
// Load the content specified by the fragment
// arguments. In a real-world scenario, use a Loader
// to load content from a content provider.
mItem = Items.ITEM_MAP.get(getArguments().getString(ARG_ITEM_ID));
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(android.R.layout.titles_fragment, container, false);
// Show the content as text in a TextView.
if (mItem != null) {
((TextView) rootView.findViewById(android.R.id.textTitle2)).setMovementMethod(new ScrollingMovementMethod());
}
return rootView;
}
}
Finally I have an ActivityFragment that implements "YouTubePlayer.OnInitializedListener" and from which I get the fragment.
public class ItemDetailActivity extends FragmentActivity implements YouTubePlayer.OnInitializedListener{
private TextView mTextView;
private ImageView hImageView;
private ImageView lImageView;
public static final String API_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
public static final String VIDEO_ID = "BJVlU7d-4x0";
private YouTubePlayer youTubePlayer;
private YouTubePlayerFragment youTubePlayerFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_detail);
if (savedInstanceState == null) {
// Create the detail fragment and add it to the activity
// using a fragment transaction.
fragmentTransaction(getIntent().getStringExtra(ItemDetailFragment.ARG_ITEM_ID));
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpTo(this, new Intent(this, ItemListActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onInitializationFailure(YouTubePlayer.Provider provider,
YouTubeInitializationResult result) {
Toast.makeText(this,
"YouTubePlayer.onInitializationFailure(): " + result.toString(),
Toast.LENGTH_LONG).show();
}
@Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer player,
boolean wasRestored) {
Toast.makeText(getApplicationContext(),
"YouTubePlayer.onInitializationSuccess()",
Toast.LENGTH_LONG).show();
if (!wasRestored) {
player.cueVideo(VIDEO_ID);
}
}
private void fragmentTransaction(String id) {
Bundle arguments = new Bundle();
Fragment fragment;
String content = Items.ITEM_MAP.get(id).content;
if(content.equalsIgnoreCase("Title 1")) {
// Fragment transaction
arguments.putString(ItemDetailFragment.ARG_ITEM_ID, id);
fragment = new ItemDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.item_detail_container, fragment)
.commit();
}
if(content.equalsIgnoreCase("Title 2")) {
// Fragment transaction
arguments.putString(ItemDetailFragment.ARG_ITEM_ID, id);
fragment = new MyFragment);
fragment.setArguments(arguments);
FragmentManager fm = getSupportFragmentManager();
//youTubePlayerFragment = fragment.getChildFragmentManager().findFragmentById(R.id.youtubeplayer_fragment);
//youTubePlayerFragment = (YouTubePlayerFragment)getFragmentManager().findFragmentById(R.id.youtubeplayer_fragment);
//Fragment ytbfragment = fragment.getChildFragmentManager().findFragmentById(R.id.youtubeplayer_fragment);
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.item_detail_container, fragment);
//ft.add(R.id.youtubeplayer_fragment, youTubePlayerFragment);
ft.commit();
//youTubePlayerFragment.initialize(API_KEY, this);
}
if(content.equalsIgnoreCase("Title 3")) {
// Fragment transaction
arguments.putString(ItemDetailFragment.ARG_ITEM_ID, id);
fragment = new ItemDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.item_detail_container, fragment)
.commit();
}
}
}
In the Title 2 is where I get the fragment and where I'm trying to get the inside fragment of the youtube player with different methods, but it does not works. Always crash loading the .xml trying to get the player form the when I try to get de YoutubeFragment.
If I only load the original fragment, the app gets the xml file well.
Whats the problem?
I've been working on this issue for days now, and I've finally found a solution. I'll post the code here ok?
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View fragmentYoutubeView = inflater.inflate(R.layout.fragment_youtube, container, false);
mYoutubePlayerFragment = new YouTubePlayerSupportFragment();
mYoutubePlayerFragment.initialize(youtubeKey, this);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_youtube_player, mYoutubePlayerFragment);
fragmentTransaction.commit();
mYoutubeVideoTitle = (TextView)fragmentYoutubeView.findViewById(R.id.fragment_youtube_title);
mYoutubeVideoDescription = (TextView)fragmentYoutubeView.findViewById(R.id.fragment_youtube_description);
mYoutubeVideoTitle.setText(getArguments().getString(Resources.KEY_VIDEO_TITLE));
mYoutubeVideoDescription.setText(getArguments().getString(Resources.KEY_VIDEO_DESC));
VideoFragment.setTextToShare(getArguments().getString(Resources.KEY_VIDEO_URL));
return fragmentYoutubeView;
}
In this code I pass through an Intent the youtube video ID (url), the title and description and put these in textViews. To play the youtubePlayerFragment I use a frameLayout (fragment_youtube_player) just like this:
<FrameLayout
android:id="@+id/fragment_youtube_player"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
I put weight 1 because the LinearLayout containing the Frame and textViews has a weight of 3, to force the views to occupy the space I tell them to.
The kit of the question is here:
mYoutubePlayerFragment = new YouTubePlayerSupportFragment();
mYoutubePlayerFragment.initialize(youtubeKey, this);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_youtube_player, mYoutubePlayerFragment);
fragmentTransaction.commit();
This code replaces the FrameLayout with a youtubePlayerSupportFragment programmatically. All this is inside an Android fragment, and it works.
EDIT 1:
I've seen some confusion about how the Fragment manages the initalization success and failure of Youtube's API. To clarify my Fragment header looks like this:
public class FragmentYoutubePlayerGenerator extends Fragment
implements YouTubePlayer.OnInitializedListener{
And the two methods to implement are quite simple:
@Override
public void onInitializationSuccess(Provider provider,
YouTubePlayer player,
boolean wasRestored) {
if(!wasRestored){
player.cueVideo(mVideoInfo.getId());
}
}
@Override
public void onInitializationFailure(Provider provider,
YouTubeInitializationResult result) {
if (result.isUserRecoverableError()) {
result.getErrorDialog(this.getActivity(),1).show();
} else {
Toast.makeText(this.getActivity(),
"YouTubePlayer.onInitializationFailure(): " + result.toString(),
Toast.LENGTH_LONG).show();
}
}
I leave to the developer's choice to leave or not the result.toString() in the error handling, some user's won't like seeing a lot of numbers that they don't understand on their screens but it's also good to put them because they can snapshot it and send them to you to debug the error.