java.lang.IllegalStateException: YouTubeServiceEnt

2020-05-25 06:03发布

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!

3条回答
走好不送
2楼-- · 2020-05-25 06:29

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.

查看更多
小情绪 Triste *
3楼-- · 2020-05-25 06:35

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
4楼-- · 2020-05-25 06:42

this code is written in xamarin.android, should help

 public class PlayerActivity : YouTubeBaseActivity, IYouTubePlayerOnInitializedListener, IYouTubePlayerPlayerStateChangeListener
{
    private int RECOVERY_DIALOG_REQUEST = 1;
    public static string DEVELOPER_KEY = "key";
    IYouTubePlayer player;



    //  public static string VIDEO_ID = "_OBlgSz8sSM";
    public void OnInitializationFailure(IYouTubePlayerProvider p0, YouTubeInitializationResult p1)
    {
        if (p1.IsUserRecoverableError)
        {

            p1.GetErrorDialog(this, RECOVERY_DIALOG_REQUEST).Show();
        }
        else
        {
            string errorMessage = string.Format(
                    "ERROR", p1.ToString());
            Toast.MakeText(this, errorMessage, ToastLength.Long).Show();
        }
    }

    public void OnInitializationSuccess(IYouTubePlayerProvider p0, IYouTubePlayer p1, bool p2)
    {


        //  YouTubeItem item = JsonConvert.DeserializeObject<YouTubeItem>(Intent.GetStringExtra("VideoID"));
        YouTubeItem itrm = new YouTubeItem();
        itrm.VideoId = Intent.GetStringExtra("VideoID2");
        string VIDEO_ID = itrm.VideoId;
        p1.LoadVideo(VIDEO_ID);
        player = p1;

        p1.SetPlayerStateChangeListener(this);

    }
    protected override void OnCreate(Bundle savedInstanceState)
    {


        base.OnCreate(savedInstanceState);

        SetContentView(Resource.Layout.PlayerLayout);

        YouTubePlayerView youTubeView = FindViewById<YouTubePlayerView>(Resource.Id.youtubeView);
        youTubeView.Initialize(DEVELOPER_KEY, this);
        // Create your application here
    }

    public void OnAdStarted()
    {

    }

    public void OnError(YouTubePlayerErrorReason p0)
    {

    }

    public void OnLoaded(string p0)
    {


    }

    public void OnLoading()
    {


    }

    public void OnVideoEnded()
    {





        }
    }

    public void OnVideoStarted()
    {

    }
查看更多
登录 后发表回答