使用YouTubePlayerApi时出现java.lang.IllegalStateException: YouTubeServiceEntity未初始化错误

36

我在我的应用程序中使用YouTubePlayerAPIYouTubePlayerSupportFragment,但是我遇到了以下错误,但我找不出是什么原因导致的。我一直在寻找信息,但我没有找到任何有用的东西。

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)

在堆栈跟踪中,没有任何行号指向我的任何类或活动。

有什么想法吗?

谢谢!

编辑

我的自定义YoutubePlayerFragment类: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>

调用方法:

// 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();

编辑

我已经找出那个错误的起源。这是情况:

活动启动。在 onCreate() 中,它实例化一个新的 YouTubeVideoPlayerFragment 并在其 newInstance() 方法中初始化 YouTube 对象(该对象在内部启动了 YouTubeServiceEntity)。然后先前实例化的 YouTube 片段在视频加载时通过 FragmentManager 附加到相应的 FrameLayout

这里是问题所在:如果用户在视频加载完成之前退出活动,则会引发异常。

因此,在这种情况下,如果用户想退出活动,我应该做什么以及如何做?我真的不知道该怎么办!


1
你能展示一下你初始化YouTubeServiceEntity的代码吗? - Syeda Zunaira
你有没有找到解决这个问题的方法? - Scott Cooper
1
我正在使用Youtube API,但是一直遇到这个错误。你找到解决方案了吗? - Huy Duong Tu
@HuyDuongTu 还没有。我还没有猜到如何检查初始化是否已经完成,就像那个链接中的用户回答的那样:https://code.google.com/p/gdata-issues/issues/detail?id=6582 - GmloMalo
实际视图是在哪里声明的?我的意思是说,YouTubePlayerView在哪里? - paul_hundal
显示剩余8条评论
4个回答

4
再次强调,不要使用片段构造函数或工厂方法来处理与生命周期或上下文相关的实体。简单地说,在调用super.onCreate(...)之后才能使用这些实体。
现在的问题是,何时调用init方法?
以下是 YouTubePlayerFragment文档中的说明:
“与此片段相关联的YouTubePlayer将在其onDestroyView()方法被调用时释放。因此,每当与此片段相关联的活动重新创建时,即使通过设置setRetainInstance(boolean)保留了片段实例,您也必须重新调用initialize(String, YouTubePlayer.OnInitializedListener)。”
你可能会想把init()放在onActivityCreated里面,但那太晚了,因为onStart已经被调用并且布局已经执行。
onDestroyView相对应的是onViewCreated,这是最理想的选择。
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    init();
}

建议在片段的构造函数中调用setRetainInstance(true)。当Activity重新创建时,Fragment不会重新创建,只有其UI将经历生命周期事件。


我只使用带有YouTube播放器的活动,但仍然从Google控制台收到关于此问题的一些报告:“java.lang.IllegalStateException android.os.Parcel.readException”。因此,这与片段无关(我不使用它们)。 - user25
我在onResume()中调用init()仍然崩溃了..有什么想法吗? - Astha Garg
我在onViewCreated中调用init()并遇到了同样的错误。 - Duna
1
@Duna 看起来是保存状态的问题。通过进入开发人员设置并勾选 不保留活动 选项来模拟状态恢复。然后启动播放器,按 Home 键,再返回到播放器。它应该会崩溃。打开一个新的 SO 问题,并附上完整的堆栈跟踪信息。 - Eugen Pechanec

1

0
问题在于Youtube片段的初始化。您必须在自己的类中扩展YouTubePlayerSupportFragment并覆盖一些方法。您需要控制屏幕方向和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);
    }
  }

包含Youtube片段的活动

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();
        }
      }
    }

我相信这与片段无关,因为我仅在活动中使用时遇到了此问题:https://github.com/youtube/yt-android-player/issues/23 - user25
我已经限制了屏幕方向的更改,但仍然出现崩溃。有什么想法吗? - Astha Garg

0
我可以通过使用 ProgressDialog 等待播放器加载来修复此错误。

目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接