Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to retain instance of fragment of fragment playing video after change in orientation?

I have a YouTube API fragment that is statically added in my xml manifest file, i.e. a fragment that has a youtube player inside of it.

I do not have a file that extends fragment in my project.

In my activity class I put this line of code in the onCreate of my activity class:

youTubePlayerFragment.setRetainInstance(true);

It does not have any affect: when I rotate the screen I get a blank black screen of the fragment.

How can I get it to continue playing the fragment after the orientation change?

<fragment
      android:id="@+id/youtube_fragment"
      android:name="com.google.android.youtube.player.YouTubePlayerFragment"
      android:layout_width="900dp"
      android:layout_height="500dp"
      android:layout_centerHorizontal="true"
      android:layout_centerVertical="true" />
like image 934
Kevik Avatar asked Apr 08 '13 04:04

Kevik


People also ask

How do you retain fragments?

You can create a Fragment that has no UI and just use it to store all the data and long-running tasks you have across configuration changes. This works because when you are using Fragment#setRetainInstance() , your Fragment will not be destroyed when the Activity is destroyed.

Is it possible to reuse a fragment in multiple screens?

Yes you can, but you have to add more logic to your fragments and add some interfaces for each activity.

Are fragments destroyed when activity is destroyed?

A paused Fragment is still alive (all state and member information is retained by the system), but it will be destroyed if the Activity is destroyed. If the user presses the Back button and the Fragment is returned from the back stack, the lifecycle resumes with the onCreateView() callback.

Are fragments reusable?

A Fragment represents a reusable portion of your app's UI. A fragment defines and manages its own layout, has its own lifecycle, and can handle its own input events. Fragments cannot live on their own--they must be hosted by an activity or another fragment.


2 Answers

The quick and easy solution is to add the following to your video activity, in your manifest:

android:configChanges="orientation|keyboard|keyboardHidden|screenSize"

I have an app that uses this for a video and it works just fine. Everything lays out properly on orientation change, and the activity and fragment instance do not get torn down allowing it to seamlessly continue to play.

If you want the activity to be torn down/recreated, while retaining the fragment instance, please re-read the documentation for setRetainInstance(). There are some subtle nuances that you need to be aware of to get this to work properly: http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance(boolean)

like image 93
Eric Schlenz Avatar answered Sep 28 '22 07:09

Eric Schlenz


Every time orientation changes the activity will be recreated as long as with all child components. Now the important part is that, YouTubePlayer.Provider will hold its stages(such as:loaded videos, the current playback position and player configurations). Have a look at the following:

YouTubePlayer Overview

In your case, after the orientation changes, the activity is recreated as long as its child fragment(youTubePlayerFragment). So you lost the reference of the YouTubePlayer's instant and the data(such as videoID or video url) which are necessary to load the video, But the YouTubePlayer's provider is still holding the previous state, which become null after the rotation.

Solution: you actually need to manage a way to save the data necessary for playing the video on YouTubePlayer before the device change the orientation, and to retrieve the data back when the activity is recreated. Have a look at the following:

YouTubePlayerFragment Overview

Not sure about your code structure, but hope the following code will give you some idea:

 @Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putString("currentVideoID",videoID);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    videoID = savedInstanceState.getString("currentVideoID");
}

A sample to get the video playing on youtubeplayer

private void loadYouTubePlayer(){
    //load your youTubePlayerFragment here, i used YouTubePlayerSupportFragment(),may change in your case
    //also you may not need to call getActivity(). Change the code as require
    youTubePlayerFragment = (YouTubePlayerSupportFragment)getActivity().getSupportFragmentManager().findFragmentById(R.id.youtube_fragment);
    youTubePlayerFragment.initialize(developerKey,new YouTubePlayer.OnInitializedListener() {
        @Override
        public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean b) {
            myYouTubePlayer = youTubePlayer;
            myYouTubePlayer.setFullscreenControlFlags(YouTubePlayer.FULLSCREEN_FLAG_CONTROL_ORIENTATION | YouTubePlayer.FULLSCREEN_FLAG_ALWAYS_FULLSCREEN_IN_LANDSCAPE);
            myYouTubePlayer.setOnFullscreenListener(new YouTubePlayer.OnFullscreenListener() {
                @Override
                public void onFullscreen(boolean b) {
                    isFullScreenPlaying = b;
                    Log.d(null,"Now fullScreen");
                }
            });
            if (!b) {
                myYouTubePlayer.loadVideo(videoID);
            }
        }

        @Override
        public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {
        Log.e(null,"Initialization Failed !!!");
        }
    });
}
like image 30
Shad Avatar answered Sep 28 '22 07:09

Shad