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

Posted

技术标签:

【中文标题】java.lang.IllegalStateException:使用 YouTubePlayerApi 时 YouTubeServiceEntity 未初始化错误【英文标题】:java.lang.IllegalStateException: YouTubeServiceEntity not initialized error when using YouTubePlayerApi 【发布时间】:2015-02-19 04:52:41 【问题描述】:

我在我的应用程序中使用 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)

在 stackstrace 中没有任何行号指向我的任何类或活动。

你知道吗?

谢谢!

编辑

我的自定义 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);
            
    

片段.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    android:layout_
    android:layout_
    android:background="@color/black" >

    <!-- For YoutubeFragment -->
    <FrameLayout
        android:id="@+id/youtube_fragment"
        android:layout_
        android:layout_ />

</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

问题如下:如果用户在视频加载之前退出活动,则会引发异常。

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

【问题讨论】:

您能否在初始化 YouTubeServiceEntity 的位置显示您的代码 编辑代码@Zoya 对不起,我仍然无法找到 YouTubeServiceEntity 的初始化。并且您的 logcat 也报告了同样的问题 对不起!我不直接初始化 YouTubeServiceEntity。我想它是通过 YouTubePlayerApi jar 库初始化的 我正在使用 Youtube api 并且非常面临这个错误。您找到解决方案了吗? 【参考方案1】:

我看到华为手机报告了同样的错误。

我在这里看到了解释:

https://github.com/youtube/yt-android-player/issues/23

不确定是否有办法在我们的代码中捕获异常。

【讨论】:

【参考方案2】:

此代码是用 xamarin.android 编写的,应该有所帮助

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

    

【讨论】:

它有什么帮助?库 (.jar) 中存在问题【参考方案3】:

问题在于 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();
        
      
    

【讨论】:

我相信它与片段无关,因为我只使用活动就遇到了这个问题:github.com/youtube/yt-android-player/issues/23 我限制了屏幕方向的改变,但我仍然遇到这个崩溃..有什么想法吗?【参考方案4】:

再一次,不要使用片段构造函数或工厂方法来处理生命周期或上下文绑定的实体。简单来说,这种实体只有在super.onCreate(...)被调用后才能使用。

现在的问题是,什么时候调用init 方法?

YouTubePlayerFragment documentation 是这样说的:

每当调用其onDestroyView() 方法时,将释放与此片段关联的YouTubePlayer。因此,无论何时重新创建与此片段关联的活动时,您都必须重新调用initialize(String, YouTubePlayer.OnInitializedListener),即使通过设置setRetainInstance(boolean) 在重新创建活动时保留片段实例。

您可能想将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。所以这与片段无关(我不使用它们) 我从 onResume() 调用 init() 仍然会崩溃..有什么想法吗? 我在 onViewCreated 中调用 init() 并得到相同的错误 @Duna 看起来像是保存状态的问题。通过转到开发人员设置来模拟状态恢复并在最后检查Don't keep activities 选项。然后启动播放器,按 Home,然后返回播放器。它应该崩溃。使用整个堆栈跟踪打开一个新的 SO 问题。

以上是关于java.lang.IllegalStateException:使用 YouTubePlayerApi 时 YouTubeServiceEntity 未初始化错误的主要内容,如果未能解决你的问题,请参考以下文章