How to play a video with the YouTube API using YouTubePlayerFragment? - android

I'm trying to play video in my Fragment. However, I cannot get it to work. If I'm extending 'YoutubeFailureRecovery' I get:
09-06 21:56:40.472: E/AndroidRuntime(4946): Caused by: java.lang.IllegalStateException: A YouTubePlayerView can only be created with an Activity which extends YouTubeBaseActivity as its context.
This is my .xml:
<com.google.android.youtube.player.YouTubePlayerView
android:id="#+id/player"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
And this is the class:
public class YoutubeFragment extends YoutubeFailureRecovery {
YouTubePlayer player;
YouTubePlayerView playerView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle arg2) {
// TODO Auto-generated method stub
return inflater.inflate(R.layout.detailview, container, false);
}
#Override
public void onStart() {
// TODO Auto-generated method stub
super.onStart();
playerView = (YouTubePlayerView)getActivity().findViewById(R.id.player);
playerView.initialize(DataHolder.DEVELOPER_KEY, this);
}
#Override
public void onInitializationSuccess(Provider provider, YouTubePlayer player,
boolean wasRestored) {
// TODO Auto-generated method stub
player.cueVideo("nCgQDjiotG0");
}
#Override
protected Provider getYouTubePlayerProvider() {
// TODO Auto-generated method stub
return playerView;
}
}
public abstract class YoutubeFailureRecovery extends YouTubePlayerSupportFragment implements YouTubePlayer.OnInitializedListener{
I just don't know what to do. I tried to extend my Fragment class with 'YoutubePlayerSupportFragment', tried to add a video-like fragment in XML, but nothing is working (error inflating). Maybe someone has some experience with using YouTube API in Fragment?

The YouTubePlayerView only works with an Activity that extends
YouTubeBaseActivity.
If you want to use Fragments you have to use the YoutubePlayerFragment / SupportFragment.
You can for example create your custom Fragment that inherits from YoutubePlayerSupportFragment:
public class VideoFragment extends YouTubePlayerSupportFragment {
public VideoFragment() { }
public static VideoFragment newInstance(String url) {
VideoFragment f = new VideoFragment();
Bundle b = new Bundle();
b.putString("url", url);
f.setArguments(b);
f.init();
return f;
}
private void init() {
initialize("yourapikey", new OnInitializedListener() {
#Override
public void onInitializationFailure(Provider arg0, YouTubeInitializationResult arg1) { }
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer player, boolean wasRestored) {
if (!wasRestored) {
player.cueVideo(getArguments().getString("url"));
}
}
});
}
}
In code it could look like this:
VideoFragment f = VideoFragment.newInstance("your-video-url");
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, f).commit();
The "fragment_container" in this case should be an empty FrameLayout.

Related

Use YoutubePlayerView on fragment section

I found some similar situation, like this and this, but none of then solved my problem.
I have wanna have a screen with youtube video and some text information like this:
I'm using a activity and a fragment, both with base class that extended YouTubeBaseActivity and YouTubePlayerFragment.
But when I'm trying to open the fragment it show a npe but it don't show where. Since I'm getting the layout and view right, I don't now what is going on.
Hope that it don't get downvotes because is a npe question, but is different from usual, this API call don't show me where the NPE happen and I saw the other people has problems like this
Obs: I'm using this extend base concept because more places will have this videos behaviour and I'm trying to avoid code repeat.
Logcat
XML
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".screens.mine.fragments.MineStepsFragment">
<com.google.android.youtube.player.YouTubePlayerView
android:id="#+id/mine_steps_youtube_player"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#color/background_white"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
</com.google.android.youtube.player.YouTubePlayerView>
</android.support.constraint.ConstraintLayout>
Activity
public class MineAccidentActivity extends BaseYoutubeActivity {
#Override
protected void initializeActionBar() {
actionbarLeftBtn.setVisibility(View.VISIBLE);
actionbarTitle.setVisibility(View.VISIBLE);
}
#Override
protected int getActionbarTitle() {
return R.string.mine_accident;
}
#Override
protected int getContentView() {
return R.layout.mine_accident_activity;
}
#Override
protected void assignViews() {
MineAccidentController.getInstance().attachToActivity(this, R.id.mine_container);
}
#Override
protected void prepareViews() {}
/////////////////// BACK ////////////////////
#Override
public void onBackPressed() {
if (!MineAccidentController.getInstance().isFirstFragmentShown()) {
MineAccidentController.getInstance().showPreviousFragment();
} else {
super.onBackPressed();
}
}
/////////////////// LIFE CYCLE ////////////////////
#Override
protected void onDestroy() {
MineAccidentController.getInstance().onDestroy();
super.onDestroy();
}
}
Fragment Controller
public class MineAccidentController extends BaseYoutubeController {
private String accidentType;
#Override
protected ArrayList<android.app.Fragment> initFragments() {
ArrayList<android.app.Fragment> fragments = new ArrayList<>();
fragments.add(new MineStepsFragment());
return fragments;
}
//create Class
public static MineAccidentController getInstance() {
if (null == instance) {
synchronized (MineAccidentController.class) {
if (null == instance) {
setInstance(new MineAccidentController());
}
}
}
return (MineAccidentController) instance;
}
public String getAccidentType() {
return accidentType;
}
public void setAccidentType(String accidentType) {
this.accidentType = accidentType;
}
}
Fragment
public class MineStepsFragment extends BaseYoutubeFragment {
//Not in Layout
private String videoUrl;
////////////// IMPLEMENT_METHODS //////////////
#Override
protected int getFragmentContentView() {
return R.layout.mine_steps_fragment;
}
#Override
protected int getYoutubePlayerView() {
return R.id.mine_steps_youtube_player;
}
#Override
protected void assignViews() {
}
#Override
protected void prepareViews() {
}
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean wasRestored) {
if(!wasRestored){
checkType();
youTubePlayer.cueVideo(videoUrl);
}
}
#Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {
showErrorToast(getActivity(), R.string.error_initialize_video);
}
////////////// FUNCTIONS //////////////
private void checkType() {
if(MineAccidentController.getInstance().getAccidentType().equals(Parameters.ACCIDENT_PERSONAL)){
videoUrl = Properties.MINE_PERSONAL_VIDEO;
}
else {
videoUrl = Properties.MINE_WORK_VIDEO;
}
}
}
Base Fragment
public abstract class BaseYoutubeFragment extends YouTubePlayerFragment implements YouTubePlayer.OnInitializedListener {
protected View fragmentView = null;
protected YouTubePlayerView youTubePlayerView;
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
assignViews();
prepareViews();
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
fragmentView = inflater.inflate(getFragmentContentView(), container, false);
youTubePlayerView = fragmentView.findViewById(getYoutubePlayerView());
youTubePlayerView.initialize(com.can_apps.eva_ngo.properties.Properties.API_KEY, this);
return fragmentView;
}
/////////////////// ABSTRACT METHODS ////////////////////
protected abstract int getFragmentContentView(); //Get Layout R.layout.name_file
protected abstract int getYoutubePlayerView(); //Get Container for YOutube Video
protected abstract void assignViews(); //Used for findById the params
protected abstract void prepareViews(); //Used for start the values of params
/////////////////// SHOW MESSAGES ////////////////////
public void showErrorToast(Context context, final int message) {
Toast toast = Toast.makeText(context, getString(message), Toast.LENGTH_SHORT);
View view = toast.getView();
view.setBackgroundResource(R.color.background_red_transparent);
toast.show();
}
/////////////////// SNACK BAR ////////////////////
public void showSnackBar(final int text) {
Snackbar.make(Objects.requireNonNull(getView()), getString(text), Snackbar.LENGTH_SHORT).show();
}
public void showSnackBar(final int mainTextStringId, final int actionStringId, View.OnClickListener listener) {
Snackbar.make(Objects.requireNonNull(getView()),
getString(mainTextStringId),
Snackbar.LENGTH_LONG)
.setAction(getString(actionStringId), listener).show();
}
}
Looking at the logcat it looks like your YouTubePlayerView is null when you are calling one of its methods.
The YouTube Player API is quite buggy and difficult to use correctly. To solve this problems (and others) I have built an alternative player Android-YouTube-Player, it's open source and you can do whatever you want with it.
In your case, you won't have to meddle with Fragments and transactions, since my YouTubePlayerView is just a regular view and requires no special Fragments or Activities. You can drop it wherever you want.
Hope it could be useful to you as well!

YoutubePlayerSupportFragment inside Viewpager

I have about 5 different videos from youtube and I want to put them into viewpager to slide them. Is there any solution for this with explanation, because I searched here and at different sites, but can't find something useful. Thank you for attention
You have to call YouTubePlayerSupportFragment.reset() on the old YouTubePlayer when the ViewPager is switched and then YouTubePlayerSupportFragment.initialize(). This requires responding to the TabLayout's onTabSelected events which cant use .setupWithViewPager (which swallows both the ViewPager and TabLayouts view change events). This is roughly what's needed in the adapter (initialisePlayer and shutDownPlayer are called in response to tab changes, in the fragment that sets up the adapter, ViewPager and TabLayout):
private SparseArray<YouTubePlayerSupportFragment> fragments = new SparseArray<>(3);
private SparseArray<YouTubePlayer> players = new SparseArray<>(3);
#Override
public android.support.v4.app.Fragment getItem(final int position) {
YouTubePlayerSupportFragment fragment = new YouTubePlayerSupportFragment();
fragments.put(position, fragment);
return fragment;
}
public void initialisePlayer(final int position) {
YouTubePlayerSupportFragment fragment = fragments.get(position);
fragment.initialize(API_KEY, new YouTubePlayer.OnInitializedListener() {
#Override
public void onInitializationSuccess(final YouTubePlayer.Provider provider, final YouTubePlayer youTubePlayer, final boolean b) {
players.put(position, youTubePlayer);
youTubePlayer.cueVideo(getVids()[position]);
}
#Override
public void onInitializationFailure(final YouTubePlayer.Provider provider, final YouTubeInitializationResult youTubeInitializationResult) {
}
});
}
public void shutDownPlayer(int position) {
YouTubePlayer player = players.get(position);
if (player == null) {
return;
}

java.lang.IllegalStateException: YouTubeServiceEntity not initialized error when using YouTubePlayerApi

I'm using YouTubePlayerAPI and YouTubePlayerSupportFragment in my app and I'm getting the following error, but I couldn't find out what is causing it. I've been looking for information but I haven't found anything useful.
java.lang.IllegalStateException: YouTubeServiceEntity not initialized
at android.os.Parcel.readException(Parcel.java:1433)
at android.os.Parcel.readException(Parcel.java:1379)
at com.google.android.youtube.player.internal.l$a$a.a(Unknown Source)
at com.google.android.youtube.player.internal.o.a(Unknown Source)
at com.google.android.youtube.player.internal.ad.a(Unknown Source)
at com.google.android.youtube.player.YouTubePlayerView.a(Unknown Source)
at com.google.android.youtube.player.YouTubePlayerView$1.a(Unknown Source)
at com.google.android.youtube.player.internal.r.g(Unknown Source)
at com.google.android.youtube.player.internal.r$c.a(Unknown Source)
at com.google.android.youtube.player.internal.r$b.a(Unknown Source)
at com.google.android.youtube.player.internal.r$a.handleMessage(Unknown Source)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5041)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
at dalvik.system.NativeStart.main(Native Method)
In the stackstrace there isn't any line number pointing to any of my classes or activities.
Any idea of it?
Thanks!
EDIT
My custom YoutubePlayerFragment Class: YouTubeVideoPlayerFragment.java
public class YouTubeVideoPlayerFragment extends YouTubePlayerSupportFragment {
private static final String ARG_URL = "url";
// ===========================================================
// Constructors
// ===========================================================
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public YouTubeVideoPlayerFragment() {
}
/**
* Factory method to generate a new instance of the fragment given a video URL.
*
* #param url The video url this fragment represents
* #return A new instance of this fragment with itemId extras
*/
public static YouTubeVideoPlayerFragment newInstance(String url) {
final YouTubeVideoPlayerFragment mFragment = new YouTubeVideoPlayerFragment();
// Set up extras
final Bundle args = new Bundle();
args.putString(ARG_URL, url);
mFragment.setArguments(args);
// Initialize YouTubePlayer
mFragment.init();
return mFragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
private void init(){
initialize(Constants.API_KEY, new YouTubePlayer.OnInitializedListener() {
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean wasRestored) {
if (!wasRestored) {
youTubePlayer.cueVideo(getArguments().getString(ARG_URL));
youTubePlayer.setShowFullscreenButton(false);
}
}
}
fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:background="#color/black" >
<!-- For YoutubeFragment -->
<FrameLayout
android:id="#+id/youtube_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
calling method:
// Create a new instance of YouTubeVideoPlayerFragment providing video id
// and place it in the corresponding FrameLayout
final YouTubeVideoPlayerFragment youTubeVideoPlayerFragment = YouTubeVideoPlayerFragment.newInstance(VIDEO_ID);
final FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.replace(R.id.youtube_fragment, youTubeVideoPlayerFragment);
ft.commit();
EDIT
I've found out the origin of that error. This is the scenario:
The activity starts. In onCreate() it instantiates a new YouTubeVideoPlayerFragment and initializes YouTube object (which starts the YouTubeServiceEntity internally) in its newInstance() method. Then the YouTube fragment that was instantiated before, is attached with FragmentManager to the corresponding FrameLayout while video is loading.
Here is the issue: If user exits the activity before video had been loaded, the exception is thrown.
So if user want to exit from the activity in that case, what should I do and how? I don't really know what to do!
Once again, do NOT use fragment constructors or factory methods to work with lifecycle or context bound entities. Simply put, such entities can only be used after super.onCreate(...) has been called.
The question now is, when to call the init method?
Here's what YouTubePlayerFragment documentation says:
The YouTubePlayer associated with this fragment will be released whenever its onDestroyView() method is called. You will therefore have to re-call initialize(String, YouTubePlayer.OnInitializedListener) whenever the activity associated with this fragment is recreated, even if the fragment instance is retained across activity re-creation by setting setRetainInstance(boolean).
You may be tempted to put init() in onActivityCreated but that's too late, since onStart was already called and layout already performed.
Counterpart to onDestroyView is onViewCreated and that's the perfect candidate.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
init();
}
As suggested call setRetainInstance(true) in the fragment's constructor. When the activity is recreated the fragment will not be recreated, only its UI will go through lifecycle events.
I see the same error reported from a Huawei cellphone.
I see an explanation here:
https://github.com/youtube/yt-android-player/issues/23
Not sure if there is a way to catch the exception in our code.
The problem is the initialization of the Youtube fragment. YouTubePlayerSupportFragment has to be extended in a class of yours and overrides some methods. You have to control the screen orientation and the onSaveInstanceState.
public class YouTubePlayerFragment extends YouTubePlayerSupportFragment {
private YouTubePlayer mPlayer;
public static YouTubePlayerFragment newInstance() {
return new YouTubePlayerFragment();
}
#Override public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setRetainInstance(true);
}
#Override
public void initialize(String s, YouTubePlayer.OnInitializedListener onInitializedListener) {
super.initialize(s, new YouTubePlayer.OnInitializedListener() {
#Override public void onInitializationSuccess(YouTubePlayer.Provider provider,
YouTubePlayer youTubePlayer, boolean b) {
mPlayer = youTubePlayer;
onInitializedListener.onInitializationSuccess(provider, youTubePlayer, b);
}
#Override public void onInitializationFailure(YouTubePlayer.Provider provider,
YouTubeInitializationResult youTubeInitializationResult) {
onInitializedListener.onInitializationFailure(provider, youTubeInitializationResult);
}
});
}
#Override public void onDestroyView() {
if (mPlayer != null) {
mPlayer.release();
}
super.onDestroyView();
}
public YouTubePlayer getPlayer() {
return mPlayer;
}
}
YoutubeFragment.class
public class YoutubeFragment extends Fragment {
private static final String EXTRA_PLAYED_VIDEO = "EXTRA_PLAYED_VIDEO";
private static final String EXTRA_IS_PLAYING = "EXTRA_IS_PLAYING";
private static final String YOUTUBE_FRAGMENT = "YOUTUBE_FRAGMENT";
private static final String EXTRA_YOUTUBE_ID = "EXTRA_YOUTUBE_ID";
private RelativeLayout youtubeLayoutContainer;
private String youtubeId;
private int playedVideo;
private boolean isPlaying;
YouTubePlayer.OnInitializedListener onInitializedListener =
new YouTubePlayer.OnInitializedListener() {
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer player,
boolean wasRestored) {
if (!wasRestored) {
setYouTubePlayer(player);
}
}
#Override public void onInitializationFailure(YouTubePlayer.Provider provider,
YouTubeInitializationResult error) {
}
};
public static YoutubeFragment newInstance(String youtubeId) {
YoutubeFragment youtubeElements = new YoutubeFragment();
Bundle bundle = new Bundle();
bundle.putString(EXTRA_YOUTUBE_ID, youtubeId);
youtubeElements.setArguments(bundle);
return youtubeElements;
}
#Override public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Nullable #Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
View mView = inflater.inflate(R.layout.view_youtube_elements_item, container, false);
initViews(mView);
initYoutubeFragment();
return mView;
}
private void initViews(View view) {
youtubeLayoutContainer = (RelativeLayout) view.findViewById(R.id.youtubeLayoutContainer);
youtubeLayoutContainer.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#TargetApi(Build.VERSION_CODES.JELLY_BEAN) #Override public void onGlobalLayout() {
FrameLayout.LayoutParams lp =
new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.MATCH_PARENT);
youtubeLayoutContainer.setLayoutParams(lp);
if (AndroidSdkVersion.hasJellyBean16()) {
youtubeLayoutContainer.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
});
}
private void initYoutubeFragment() {
try {
YouTubePlayerFragment youTubePlayerFragment2 = YouTubePlayerFragment.newInstance();
youTubePlayerFragment2.initialize(BuildConfig.YOUTUBE_DEVELOPER_KEY, onInitializedListener);
if (this.getActivity() != null && !this.getActivity().isFinishing()) {
getChildFragmentManager().beginTransaction()
.replace(R.id.youtubePlayerFragmentContent, youTubePlayerFragment2, YOUTUBE_FRAGMENT)
.commitAllowingStateLoss();
}
} catch (Exception ignored) {
}
}
public void setYouTubePlayer(final YouTubePlayer player) {
try {
if (player == null) {
return;
}
player.setShowFullscreenButton(true);
player.setPlayerStyle(YouTubePlayer.PlayerStyle.DEFAULT);
if (playedVideo >= 0) {
if (playedVideo == 0 || isPlaying) {
player.loadVideo(youtubeId, playedVideo);
} else {
player.cueVideo(youtubeId, playedVideo);
}
}
} catch (Exception ignored) {
}
}
#Override public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (savedInstanceState != null) {
playedVideo = savedInstanceState.getInt(EXTRA_PLAYED_VIDEO);
isPlaying = savedInstanceState.getBoolean(EXTRA_IS_PLAYING);
}
}
#Override public void onSaveInstanceState(Bundle outState) {
try {
YouTubePlayerFragment youTubePlayerSupportFragment =
(YouTubePlayerFragment) getChildFragmentManager().findFragmentByTag(YOUTUBE_FRAGMENT);
YouTubePlayer mPlayer = youTubePlayerSupportFragment.getPlayer();
if (mPlayer != null) {
outState.putInt(EXTRA_PLAYED_VIDEO, mPlayer.getCurrentTimeMillis());
outState.putBoolean(EXTRA_IS_PLAYING, mPlayer.isPlaying());
}
} catch (Exception ignored) {
}
super.onSaveInstanceState(outState);
}
}
Activity containing Youtube Fragment
public class YoutubeContentDataActivity extends BaseActivity {
private static final String EXTRA_YOUTUBE_VIDEO_ID = "EXTRA_YOUTUBE_VIDEO_ID";
private static final String TAG_RETAINED_FRAGMENT = "TAG_RETAINED_FRAGMENT";
public static void open(Context context, String videoId) {
Intent intent = new Intent(context, YoutubeContentDataActivity.class);
intent.putExtra(EXTRA_YOUTUBE_VIDEO_ID, videoId);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
#Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_youtube_main_container_layout);
FragmentManager fm = getSupportFragmentManager();
YoutubeFragment youtubeElementsFragment =
(YoutubeFragment) fm.findFragmentByTag(TAG_RETAINED_FRAGMENT);
// create the fragment and data the first time
if (youtubeElementsFragment == null) {
String videoId = getIntent().getStringExtra(EXTRA_YOUTUBE_VIDEO_ID);
// videoId = "17uHCHfgs60";//"ikO91fQBsTQ";
youtubeElementsFragment = YoutubeFragment.newInstance(videoId);
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.youtube_main_container, youtubeElementsFragment, TAG_RETAINED_FRAGMENT)
.commit();
}
}
#Override public void onPause() {
super.onPause();
if (isFinishing()) {
FragmentManager fm = getSupportFragmentManager();
YoutubeFragment youtubeElementsFragment =
(YoutubeFragment) fm.findFragmentByTag(TAG_RETAINED_FRAGMENT);
fm.beginTransaction().remove(youtubeElementsFragment).commit();
}
}
}
I could fix this error by using a ProgressDialog to wait until the player is loaded.

Video is not pausing in fragment ViewPager

I am using View Pager with fragment to showing image and video, I am able to show image and video properly but I have problem, when I swipe for video, then video is playing, but I swipe next or previous then video is still playing on just next or previous screen but when I move two slide next or previous then video is being stop, but why not on next or previous slide.
I search it more but I did not get any solution, any help will be appreciable.
Thanks in advance.
Here is my code:
This is Fragment Class
public class ContentFragment extends Fragment {
private final String imageResourceId;
private String type;
public ContentFragment(String imageResourceId,String type) {
System.out.println("Path In cons="+imageResourceId+"and type is="+type);
this.imageResourceId = imageResourceId;
this.type= type;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e("Test", "hello");
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.content_layout, container, false);
TouchImageView imageView = (TouchImageView) view.findViewById(R.id.touchImage);
imageView.setImageResource(R.id.touchImage);
imageView.setMaxZoom(10f);
VideoView videoView =(VideoView) view.findViewById(R.id.videoView1);
if(type.equals("image")) {
imageView.invalidate();
imageView.setVisibility(View.VISIBLE);
videoView.setVisibility(View.GONE);
try {
System.out.println("IN Content Fragment"+imageResourceId.toString());
Bitmap bmp = BitmapFactory.decodeFile(imageResourceId.toString());
imageView.setImageBitmap(bmp);
} catch(Exception e) {
System.out.println("Error Of image File"+e);
}
} else
try {
if(type.equals("video")){
videoView.invalidate();
videoView.setVisibility(View.VISIBLE);
imageView.setVisibility(View.GONE);
String path = imageResourceId.toString();
videoView.setVideoURI(Uri.parse(path));
videoView.setMediaController(new MediaController(getActivity()));
videoView.setFocusable(true);
videoView.start();
}
} catch(Exception e) {
e.printStackTrace();
}
return view;
}
}
This is pager adapter activity
public class MediaActivity extends FragmentActivity {
private MyAdapter mAdapter;
private ViewPager mPager;
public ArrayList<Content> contentList;
Context context;
LinearLayout numberOfPageLayout;
SharedPreferences sharedPreferences;
Handler progressHandler;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_media);
context=(Context) getApplicationContext();
mPager = (ViewPager) findViewById(R.id.pager);
progressHandler = new Handler();
contentList=new ArrayList<Content>();
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
contentList=new ContentDBAdapter(context).getAllContent();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
mAdapter = new MyAdapter(getSupportFragmentManager(),contentList);
mPager.setAdapter(mAdapter);
}
}.execute();
mPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int arg0) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
});
}
public static class MyAdapter extends FragmentPagerAdapter {
ArrayList <Content>contList=new ArrayList<Content>();
public MyAdapter(FragmentManager fm,ArrayList<Content> cont) {
super(fm);
this.contList=cont;
}
#Override
public int getCount() {
totalPage=contList.size();
return contList.size();
}
#Override
public Fragment getItem(int position) {
Content con=contList.get(position);
return new ContentFragment(con.getPath(),con.getType());
}
}
}
It is because ViewPager keeps offscreen fragments started. For instance you have a fragment visible to the user. ViewPager will try to keep the previous fragment (on the left side) and the next fragment (on the right side) started. This allows ViewPager performing smooth sliding when user decides to change the page, because the next and the previous pages are already prepared.
In your case the video player is not visible (offscreen), but ViewPager keeps it started as due to the behaviour described above. You can use setOffscreenPageLimit() method to change this behaviour. If you set page limit to 0, then offscreen fragments will be paused immediately. Unfortunately they will not only be paused, but stopped and detached from the activity too. This means when you return back to your fragment, it will recreate the whole layout anew. That's why you can try to override either Fragment.setUserVisibleHint() or Fragment.onHiddenChanged() and execute your pause/play logic there. ViewPager will update hidden state of a fragment depending on whether the fragment is actually visible to user or not.
Hope this helps.
You have to override setUserVisibleHint method in a fragment where u play video.
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (this.isVisible())
{
if (!isVisibleToUser) // If we are becoming invisible, then...
{
//pause or stop video
}
if (isVisibleToUser)
{
//play your video
}
}
}
I handle the problem like this:
boolean isVisible = false;
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
isVisible = isVisibleToUser;
if(player!=null)
player.pause();
super.setUserVisibleHint(isVisibleToUser);
}
then in onCreateView method:
SimpleExoPlayer player;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_screen_slide_page, container, false);
PlayerView playerView = v.findViewById(R.id.playerView);
playerView.getLayoutParams().width = ListPager.widthPixels;
playerView.getLayoutParams().height = ListPager.widthPixels;
if(player!=null)
player.release();
player = new SimpleExoPlayer.Builder(App.applicationContext).build();
playerView.setPlayer(player);
MediaItem mediaItem = MediaItem.fromUri(url);
player.setMediaItem(mediaItem);
player.prepare();
//---------The following code is important because if you remove the following if
// then if the next page is displaying, android will automatically initiate the
// previous and the next page, and the player will start playing :|
if(isVisible)
player.play();
}

YouTubePlayerFragment lifecycle in a DialogFragment

I am trying to embed a YouTubePlayerFragment into a DialogFragment. I am able to start the dialog one time and show the YouTubePlayer in it, but the second time it always crashes (no matter what I do). I think it is a lifecycle problem, which I simply don't understand.
I am using AndroidAnnotations and the problem is that the view of the DialogFragment is always created in the onCreateView method, which is generated by AndroidAnnotations.
Does anyone know how to handle the lifecycle of a DialogFragment in this case?
This is the generated code from AndroidAnnotations:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
contentView_ = super.onCreateView(inflater, container, savedInstanceState);
if (contentView_ == null) {
contentView_ = inflater.inflate(layout.video_fragment, container, false);
}
return contentView_;
}
This is what I have so far:
public class VideoFragmentDialog extends DialogFragment implements YouTubePlayer.OnInitializedListener {
private static final String DEVELOPER_KEY = "secret";
private String videoUrl;
#FragmentById(R.id.youTubePlayerFragment)
YouTubePlayerFragment youTubePlayerFragment;
#AfterViews
void initializeYouTubePlayer() {
youTubePlayerFragment.setRetainInstance(true);
youTubePlayerFragment.initialize(DEVELOPER_KEY, this);
}
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean wasRestored) {
if (!wasRestored) {
youTubePlayer.cueVideo(videoUrl);
}
}
#Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {
//To change body of implemented methods use File | Settings | File Templates.
}
public String getVideoUrl() {
return videoUrl;
}
public void setVideoUrl(String videoUrl) {
this.videoUrl = videoUrl;
}
}
This is the stacktrace:
Caused by: java.lang.IllegalArgumentException: Binary XML file line #10: Duplicate id 0x7f0a0281, tag null, or parent id 0x7f0a0280 with another fragment for com.google.android.youtube.player.YouTubePlayerFragment
at android.app.Activity.onCreateView(Activity.java:4248)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:673)
I guess it's because you are using a fragment inside a fragment (Nested fragments) without using getChildFragment()
Look here for an example how to do it : nested fragments

Categories

Resources